承诺链不会等到其他承诺被解决
promise chain does not wait until other promise is resolved
我想一次执行一个函数,并在一个函数完成时调用另一个函数。我能够使用回调而不是使用承诺链来做到这一点。
这是我尝试过的(基于 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);
}
你知道代码有什么问题吗?是否可以在没有回调的情况下完成我想做的事情?
为了链接 Promise
s (MDN),您需要在 then
方法回调中 return 一个承诺,而不是将承诺构建为 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()
另一种更清晰的方法:
您还可以将显示函数 return 设为 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)
displayAll
的执行顺序演练:
-
var myPromise = (new Promise(display1))
Promise
构造函数调用 display1
设置超时以记录“display1”并解析承诺。这非常有效,最初的 1 秒延迟得到尊重。
-
.then(new Promise(display2))
- 在执行
displayAll
时调用myPromise
的then
方法。
then
的参数在调用前计算。
- 创建
then
的 promise 参数会导致 Promise 构造函数调用 display2
,从而设置相对于 displayAll
的执行时间的超时。
- 调用时
then
静静地忽略 promise 参数,因为它不是函数。默认处理程序,由 then
在没有可调用参数的情况下使用,传递传入数据或承诺拒绝原因。
-
.then(new Promise(display3))
与前面的 then
子句的操作相同:设置一个相对于 displayAll
执行时间的计时器,并使用传递数据或拒绝原因的默认处理程序。
-
.then(display4)));
将 display4
注册为处理程序,当在第 3 步中 returned 的承诺变为 fullfilled 时将被调用。 display4
设置一个可行的计时器来记录“display4”。注意 display4
的参数现在被错误命名 - 传递给后续履行处理程序的参数是链中前一个承诺处理程序的值 return。
调用 displayAll
的预期输出是
- 调用
displayAll
后延迟一秒钟并记录“display1”。
- 延迟一秒钟,在
displayAll
被调用后再次记录“display2”。
- 延迟一秒钟,在
displayAll
被调用后再次记录“display3”。
- 当 promise 链处理作为处理程序执行
display4
时,设置一个计时器来记录“display4”——因此它在“display3”之后记录一秒。
一种错开显示函数执行的解决方案是将承诺创建从 then
计算参数的位置移动到处理程序本身。处理程序可以 return 承诺延迟沿着承诺链继续进行,直到 returned 承诺被计时器解决:
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));
}
顺便说一句,promise 链的值是链中最后一个 then
、catch
或 finally
调用的 promise return - promise 链值可能 return 由函数编辑,但实际上至少很少记录在变量中。
我想一次执行一个函数,并在一个函数完成时调用另一个函数。我能够使用回调而不是使用承诺链来做到这一点。 这是我尝试过的(基于 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);
}
你知道代码有什么问题吗?是否可以在没有回调的情况下完成我想做的事情?
为了链接 Promise
s (MDN),您需要在 then
方法回调中 return 一个承诺,而不是将承诺构建为 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()
另一种更清晰的方法:
您还可以将显示函数 return 设为 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)
displayAll
的执行顺序演练:
-
var myPromise = (new Promise(display1))
Promise
构造函数调用 display1
设置超时以记录“display1”并解析承诺。这非常有效,最初的 1 秒延迟得到尊重。
-
.then(new Promise(display2))
- 在执行
displayAll
时调用myPromise
的then
方法。 then
的参数在调用前计算。- 创建
then
的 promise 参数会导致 Promise 构造函数调用display2
,从而设置相对于displayAll
的执行时间的超时。 - 调用时
then
静静地忽略 promise 参数,因为它不是函数。默认处理程序,由then
在没有可调用参数的情况下使用,传递传入数据或承诺拒绝原因。
-
.then(new Promise(display3))
与前面的
then
子句的操作相同:设置一个相对于displayAll
执行时间的计时器,并使用传递数据或拒绝原因的默认处理程序。 -
.then(display4)));
将
display4
注册为处理程序,当在第 3 步中 returned 的承诺变为 fullfilled 时将被调用。display4
设置一个可行的计时器来记录“display4”。注意display4
的参数现在被错误命名 - 传递给后续履行处理程序的参数是链中前一个承诺处理程序的值 return。
调用 displayAll
的预期输出是
- 调用
displayAll
后延迟一秒钟并记录“display1”。 - 延迟一秒钟,在
displayAll
被调用后再次记录“display2”。 - 延迟一秒钟,在
displayAll
被调用后再次记录“display3”。 - 当 promise 链处理作为处理程序执行
display4
时,设置一个计时器来记录“display4”——因此它在“display3”之后记录一秒。
一种错开显示函数执行的解决方案是将承诺创建从 then
计算参数的位置移动到处理程序本身。处理程序可以 return 承诺延迟沿着承诺链继续进行,直到 returned 承诺被计时器解决:
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));
}
顺便说一句,promise 链的值是链中最后一个 then
、catch
或 finally
调用的 promise return - promise 链值可能 return 由函数编辑,但实际上至少很少记录在变量中。