嵌套的 Promise 执行不同步
Nested Promise execution is out of sync
我有一个简单的设置,如 this fiddle 所示:
var doDelay = function(who) {
return Promise.delay(50)
.tap(function() {
console.log(who + ' done');
});
};
Promise.resolve()
.then(doDelay('a'))
.tap(function() {
console.log('a done2');
})
.then(doDelay('b'))
.tap(function() {
console.log('b done2');
})
.then(function() {
console.log('all done!');
});
输出为:
a done2
b done2
all done!
a done
b done
但我预计:
a done
b done
a done2
b done2
all done!
我做错了什么?
您不得向 then
传递承诺(立即 调用 delayMany
的结果)。相反,它期望在上下文承诺解析时执行回调 function。您需要将 delayMany
调用包装在函数表达式中:
Promise.resolve()
.then(function(undefined) { return delayMany(xsa); })
.tap(function(xsa) { console.log(xsa[0] + ' done2'); })
.then(function(xsa) { return delayMany(xsb) })
.tap(function(xsb) { console.log(xsb[0] + ' done2'); })
.then(function(xsb) { console.log('all done!'); });
正如 Bergi 指出的那样,将承诺作为参数传递给 then
是无效的,但即使它被允许,另一个问题是一旦您调用 delayMany('a')
, Promise.delay(50)
在里面它会开始执行,这不是你想要做的。
您可以将调用包装在匿名函数中,或者使用 .bind()
:
var delayMany = function(who) {
return Promise.delay(50)
.tap(function() {
console.log(who + ' done');
});
};
Promise.resolve()
.then(delayMany.bind(null, 'a'))
.tap(function() { console.log('a done2'); })
.then(delayMany.bind(null, 'b'))
.tap(function() { console.log('b done2'); })
.then(function() {
console.log('all done!');
});
问:“当我向它传递承诺时,为什么 then
没有抛出错误?”
答案在 Promises/A+ spec:
A promise’s then
method accepts two arguments:
promise.then(onFulfilled, onRejected)
2.2.1. Both onFulfilled
and onRejected
are optional arguments:
2.2.1.1. If onFulfilled
is not a function, it must be ignored.
由于您使用的是 bluebird,因此您只需使用 .delay
方法即可:
Promise.resolve()
.delay('a', 50)
.tap(function() {
console.log('a done2');
})
.delay('b', 50)
.tap(function() {
console.log('b done2');
})
.then(function() {
console.log('all done!');
});
我有一个简单的设置,如 this fiddle 所示:
var doDelay = function(who) {
return Promise.delay(50)
.tap(function() {
console.log(who + ' done');
});
};
Promise.resolve()
.then(doDelay('a'))
.tap(function() {
console.log('a done2');
})
.then(doDelay('b'))
.tap(function() {
console.log('b done2');
})
.then(function() {
console.log('all done!');
});
输出为:
a done2
b done2
all done!
a done
b done
但我预计:
a done
b done
a done2
b done2
all done!
我做错了什么?
您不得向 then
传递承诺(立即 调用 delayMany
的结果)。相反,它期望在上下文承诺解析时执行回调 function。您需要将 delayMany
调用包装在函数表达式中:
Promise.resolve()
.then(function(undefined) { return delayMany(xsa); })
.tap(function(xsa) { console.log(xsa[0] + ' done2'); })
.then(function(xsa) { return delayMany(xsb) })
.tap(function(xsb) { console.log(xsb[0] + ' done2'); })
.then(function(xsb) { console.log('all done!'); });
正如 Bergi 指出的那样,将承诺作为参数传递给 then
是无效的,但即使它被允许,另一个问题是一旦您调用 delayMany('a')
, Promise.delay(50)
在里面它会开始执行,这不是你想要做的。
您可以将调用包装在匿名函数中,或者使用 .bind()
:
var delayMany = function(who) {
return Promise.delay(50)
.tap(function() {
console.log(who + ' done');
});
};
Promise.resolve()
.then(delayMany.bind(null, 'a'))
.tap(function() { console.log('a done2'); })
.then(delayMany.bind(null, 'b'))
.tap(function() { console.log('b done2'); })
.then(function() {
console.log('all done!');
});
问:“当我向它传递承诺时,为什么 then
没有抛出错误?”
答案在 Promises/A+ spec:
A promise’s
then
method accepts two arguments:
promise.then(onFulfilled, onRejected)
2.2.1. Both
onFulfilled
andonRejected
are optional arguments:2.2.1.1. If
onFulfilled
is not a function, it must be ignored.
由于您使用的是 bluebird,因此您只需使用 .delay
方法即可:
Promise.resolve()
.delay('a', 50)
.tap(function() {
console.log('a done2');
})
.delay('b', 50)
.tap(function() {
console.log('b done2');
})
.then(function() {
console.log('all done!');
});