我正在尝试使用 Promise,并且在处理异步递归 Promise 时遇到了问题。
场景是,一名运动员开始跑100米赛跑,我需要定期检查他们是否已经完成比赛,一旦完成比赛,就打印出他们的时间。
编辑以澄清:
在现实世界中,运动员正在服务器上运行。 startRunning
涉及向服务器发出 ajax 请求。 checkIsFinished
也涉及向服务器发出 ajax 请求。下面的代码是模仿这个过程的一个尝试。为了保持简单,代码中的时间和距离都是硬编码的。对于没有表述清楚的部分表示歉意。
结束编辑
我想要编写以下代码:
startRunning()
.then(checkIsFinished)
.then(printTime)
.catch(handleError)
在哪里
var intervalID;
var startRunning = function () {
var athlete = {
timeTaken: 0,
distanceTravelled: 0
};
var updateAthlete = function () {
athlete.distanceTravelled += 25;
athlete.timeTaken += 2.5;
console.log("updated athlete", athlete)
}
intervalID = setInterval(updateAthlete, 2500);
return new Promise(function (resolve, reject) {
setTimeout(resolve.bind(null, athlete), 2000);
})
};
var checkIsFinished = function (athlete) {
return new Promise(function (resolve, reject) {
if (athlete.distanceTravelled >= 100) {
clearInterval(intervalID);
console.log("finished");
resolve(athlete);
} else {
console.log("not finished yet, check again in a bit");
setTimeout(checkIsFinished.bind(null, athlete), 1000);
}
});
};
var printTime = function (athlete) {
console.log('printing time', athlete.timeTaken);
};
var handleError = function (e) { console.log(e); };
我看到第一次创建的 checkIsFinished
的 Promise 没有被解决。如何确保该 Promise 被解决,以便调用 printTime
?
可以尝试以下方式:
resolve(athlete);
我可以做到
Promise.resolve(athlete).then(printTime);
但如果可能的话,我想要避免那种情况,我真的很想能够编写
startRunning()
.then(checkIsFinished)
.then(printTime)
.catch(handleError)
.then()
只会被执行一次,而且Promise只会被解决或拒绝一次并永远保持这样。所以,第一次到达checkIsFinished
时,你返回一个Promise,然后使用setTimeout
递归调用自己。但是这个新的Promise没有任何作用,因为setTimeout
只返回一个句柄,而不是Promise,所以这个新的Promise也保持着等待状态,然后你重复了这个过程——可能导致内存泄漏。花些时间阅读和理解JavaScript事件循环的微妙之处,这将节省你大量的时间和挫折感。 - caasjjsetTimeout(checkIsFinished.bind(null, athlete), 1000);
时,你在一个新的Promise内部创建了它,因此旧的Promise永远不会被解决。 - GrundysetTimeout(checkIsFinished.bind(null, athlete), 1000)
会创建一个新的Promise并且最初的Promise会被“丢失”。我的问题基本上是有没有办法解决这个问题?我已经编辑了问题以尝试澄清情况。 - user5325596