我想一次执行一个函数,并在一个函数完成时调用另一个函数。我能够使用回调来做到这一点,但不能使用承诺链。 这是我尝试过的(基于 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#chained_promises),但它同时执行前 3 个函数,而不是在每个函数中等待 1 秒:
function displayAll() {
var myPromise = (new Promise(display1))
.then((new Promise(display2))
.then((new Promise(display3))
.then(display4)));
}
function display1(resolve) {
setTimeout(function () {
console.log("display1");
resolve();
}, 1000);
}
function display2(resolve) {
setTimeout(function () {
console.log("display2");
resolve();
}, 1000);
}
function display3(resolve) {
setTimeout(function () {
console.log("display3");
resolve();
}, 1000);
}
function display4(resolve) {
setTimeout(function () {
console.log("display4");
}, 1000);
}
你知道代码有什么问题吗?是否可以在没有回调的情况下做我想做的事情?
答案 0 :(得分:5)
为了链接 Promise
s (MDN),您需要在 then
方法回调中返回一个承诺,而是将承诺构建为 then
方法的参数。
这将在“遇到”new
关键字时立即触发 Promise,这不是预期的行为。您希望等待第一个 Promise
结束,然后链接将创建新 then
的 Promise
方法:
function displayAll() {
var myPromise = (new Promise(display1))
// .then(new Promise(display2)) <-- you are calling here the promise
.then(function() {
return new Promise(display2) // <-- here we return a promise to chain
})
.then(()=> new Promise(display3)) // same with arrow functions
.then(display4);
}
function displayAll() {
var myPromise = (new Promise(display1))
.then(()=> new Promise(display2))
.then(() => new Promise(display3))
.then(display4);
}
function display1(resolve) {
setTimeout(function () {
console.log("display1");
resolve();
}, 1000);
}
function display2(resolve) {
setTimeout(function () {
console.log("display2");
resolve();
}, 1000);
}
function display3(resolve) {
setTimeout(function () {
console.log("display3");
resolve();
}, 1000);
}
function display4(resolve) {
setTimeout(function () {
console.log("display4");
}, 1000);
}
displayAll()
您还可以让您的显示函数返回一个 Promise
,以便您可以将它们直接传递给 then
方法:
function display1() {
return new Promise(resolve => {
setTimeout(function () {
console.log("display1");
resolve();
}, 1000);
});
}
function display2() {
return new Promise(resolve => {
setTimeout(function () {
console.log("display2");
resolve();
}, 1000);
});
}
function display3() {
return new Promise(resolve => {
setTimeout(function () {
console.log("display3");
resolve();
}, 1000);
});
}
function display4() {
return new Promise(resolve => {
setTimeout(function () {
console.log("display4");
resolve();
}, 1000);
});
}
let myPromise =
display1()
.then(display2)
.then(display3)
.then(display4)
答案 1 :(得分:1)
displayAll
的执行顺序演练:
var myPromise = (new Promise(display1))
Promise
构造函数调用 display1
设置超时以记录“display1”并解决承诺。这完美地工作,并且最初的 1 秒延迟得到尊重。
.then(new Promise(display2))
then
期间调用 myPromise
的 displayAll
方法。then
的参数。then
的 promise 参数会导致 Promise 构造函数调用 display2
,后者设置相对于 displayAll
的执行时间的超时。then
时,它会默默地忽略 promise 参数,因为它不是一个函数。 then
在没有可调用参数的情况下使用的默认处理程序传递传入数据或承诺拒绝原因。 .then(new Promise(display3))
操作与前面的 then
子句相同:设置一个相对于 displayAll
的执行时间的计时器,并使用传递数据或拒绝原因的默认处理程序。
.then(display4)));
将 display4
注册为处理程序,当第 3 步中返回的承诺已满时要调用。 display4
设置一个可行的计时器来记录“display4”。注意 display4
的参数现在被错误命名 - 传递给后续履行处理程序的参数是链中前一个承诺处理程序返回的值。
然后调用 displayAll
的预期输出是
displayAll
后延迟一秒并记录“display1”。displayAll
后再次延迟一秒钟,并记录“display2”。displayAll
后再次延迟一秒钟,并记录“display3”。display4
时,设置一个计时器来记录“display4” - 因此它会在“display3”之后记录一秒。交错执行显示函数的一种解决方案是将 Promise 创建从 then
参数计算的位置移动到处理程序本身。处理程序可以返回承诺以延迟沿着承诺链继续进行,直到返回的承诺被计时器解决:
function displayN() {
return new Promise( resolve =>
setTimer( function() {
console.log("displayN");
resolve();
}, 1000)
);
}
其他解决方案和方法也是可能的。承诺 setTimeout
以创建在指定间隔后解析的承诺对于延迟承诺链或 async
函数中的步骤非常有用。作为一个相当小的例子:
function delayPromise( msec) {
return new Promise(resolve=> setTimeout( resolve, msec));
}
顺便说一句,承诺链的值是链中最后一个 then
、catch
或 finally
调用返回的承诺 - 承诺链值可能由一个函数,但至少在实践中很少记录在变量中。