【发布时间】:2015-12-08 03:07:25
【问题描述】:
我正在使用 Promise,但我遇到了异步递归 Promise 的问题。
场景是一名运动员开始跑 100m,我需要定期检查他们是否完成,一旦完成,打印他们的时间。
编辑澄清:
在现实世界中,运动员在服务器上运行。 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 永远不会得到解决。如何确保该承诺得到解决,以便调用 printTime?
而不是
resolve(athlete);
我可以的
Promise.resolve(athlete).then(printTime);
但如果可能的话,我想避免这种情况,我真的很想能够写作
startRunning()
.then(checkIsFinished)
.then(printTime)
.catch(handleError)
【问题讨论】:
-
这段代码真的很难理解,但看起来它确实错误地使用了 Promise。除非我完全误解了这一点,否则我认为你应该花点时间重新考虑一下这个设计,也许先阅读一下 Promise。
-
您需要了解每个
.then()只执行一次,并且promise 会得到解决或拒绝一次并且永远。因此,当您第一次到达checkIsFinished时,您会返回一个待处理的承诺,然后使用setTimeout再次递归调用自己。但是这个新的承诺无处可去,因为setTimeout只是返回一个句柄,而不是一个承诺,所以这个新的承诺也保持未决,然后你重复 - 可能导致内存泄漏。花时间阅读并理解 Javascript 事件循环的精妙之处。这将为您节省大量时间和挫败感。 -
当您执行
setTimeout(checkIsFinished.bind(null, athlete), 1000);时,您会在 new Promise 中创建,所以旧的promise 永远不会解决 -
@Amit,我已经编辑了我的问题以澄清情况。
-
@caasjj,@Grundy,感谢 cmets。我知道
setTimeout(checkIsFinished.bind(null, athlete), 1000)创建了一个新的承诺,而最初的承诺“丢失”了。我的问题基本上是有办法解决这个问题吗?我已经编辑了问题以试图澄清情况。
标签: javascript asynchronous recursion promise es6-promise