Javascript 理解JS承诺
我想更深入地了解承诺是如何在内部发挥作用的。 因此,我有一些示例代码:Javascript 理解JS承诺,javascript,promise,Javascript,Promise,我想更深入地了解承诺是如何在内部发挥作用的。 因此,我有一些示例代码: var p1=新承诺( 功能(解析、拒绝){ window.setTimeout( 函数(){ 解析('rescalled') }, 2000); }); var p2=新承诺( 功能(解析、拒绝){ window.setTimeout( 函数(){ 解析('rescalled') }, 2000); }); 函数(){ 返回p1.then(函数(val){ 控制台日志(“p1”); 返回p2.then(函数(val){ 控
var p1=新承诺(
功能(解析、拒绝){
window.setTimeout(
函数(){
解析('rescalled')
}, 2000);
});
var p2=新承诺(
功能(解析、拒绝){
window.setTimeout(
函数(){
解析('rescalled')
}, 2000);
});
函数(){
返回p1.then(函数(val){
控制台日志(“p1”);
返回p2.then(函数(val){
控制台日志(“p2”);
返回val;
});
});
}
chainPromises().then(函数(val){
控制台日志(val);
});
这里是一个执行此代码的示例
正如您所预测的,首先解析p1,然后解析p2,最后最后打印resolv值
但API ref规定如下:
promiseReturning().then(function(){
alert(1);
return foo(); // foo returns a promise
}).then(function(){
alert(2); // will only run after the ENTIRE chain of `foo` resolved
// if foo OR ANY PART OF THE CHAIN rejects and it is not handled this
// will not run
});
“then”返回一个与您从中返回的值相等的新承诺
通过Promise.resolve传递后OnCompleted/onRejected
因此,了解“then”函数的确切执行时间会很有趣吗?
因为代码中的最后一个“then”链接到chainPromises(),所以我首先想到
它将在函数chainPromissions()返回某些内容(在本例中为另一个承诺)后执行
如果是这种情况,那么最终“then”函数的“val”将是返回的承诺。
但是,最终的“then”将等待,直到返回的第一个“then”中的所有承诺都得到解决。
这绝对是有道理的,因为通过这种方式,“then”函数可以堆叠,但是
我真的不明白这是怎么做到的,因为API规范没有真正涵盖“then”返回的内容以及“then”函数的执行时间
或者换句话说,为什么最终的“then”函数要等到所有承诺都在chainPromissions()函数中解析,而不是像API文档所说的那样,只等待第一个返回的对象
我希望我能弄清楚我的意思……) 让我们从一个简单的角度开始:“chainPromises”返回一个承诺,因此您可以这样看:
// Do all internal promises
var cp = chainPromises();
// After everything is finished you execute the final "then".
cp.then(function(val) {
console.log(val);
});
一般来说,当从“then”子句中返回一个承诺时,只有在内部“then”完成之后,封装承诺的“then”功能才会标记为完成
因此,如果“a”是承诺,“b”是承诺:
// "a"'s "then" function will only be marked as finished after "b"'s "then" function has finished.
var c = a.then(function () {
return b.then(function () {
console.log("B!");
};
};
// c is a promise, since "then" always returns a promise.
c.then(function() {
console.log("Done!");
};
因此,输出将是:
B!
Done!
请注意,如果您不“返回”内部承诺,则不会出现这种情况:
// "a"'s "then" function will only be marked as finished without waiting for "b"'s "then" to finish.
var c = a.then(function () {
// Notice we're just calling b.then, and don't "return" it.
b.then(function () {
console.log("B!");
};
};
// c is a promise, since "then" always returns a promise.
c.then(function() {
console.log("Done!");
};
在这里,我们无法知道将首先输出什么。它可以是“B!”或“Done!”。我不知道在实际的promises库中是如何实现的,但我能够通过以下方式重新创建此功能: 1) 每个承诺都有一个waitingPromises属性; 2) 然后方法返回一个新的承诺,并且原始承诺的waitingPromises属性指向新承诺
通过这种方式,.then()s链创建了一个类似于链表或树的结构(每个承诺可以有几个等待承诺)。承诺只有在其“父”承诺得到解决后才能得到解决。.then方法本身会立即执行,但它创建的相应承诺只会在以后解决。 我不确定这是否是一个好的解释,我希望了解其他可能的方法。关于承诺解决方案 您在这里看到的东西被称为递归
然后
可解析。承诺/A+规范中的承诺解决流程包含以下条款:
OnCompleted或onRejected返回一个值x,运行承诺解决过程[[Resolve]](promise2,x)
ES6承诺规范(承诺展开)包含类似的条款
这要求当发生resolve
操作时:在承诺构造函数中,通过调用promise.resolve
或在中,然后
链接承诺实现必须递归地打开返回值(如果它是承诺)
实际上
这意味着,如果oncompleted
(thethen
)返回一个值,则尝试自己“解析”承诺值,从而递归地等待整个链
这意味着:
promiseReturning().then(function(){
alert(1);
return foo(); // foo returns a promise
}).then(function(){
alert(2); // will only run after the ENTIRE chain of `foo` resolved
// if foo OR ANY PART OF THE CHAIN rejects and it is not handled this
// will not run
});
例如:
promiseReturning().then(function(){
alert(1);
return Promise.resolve().then(function(){ throw Error(); });
}).then(function(){
alert("This will never run");
});
而且:
promiseReturning().then(function(){
alert(1);
return Promise.resolve().then(function(){ return delay(2000); });
}).then(function(){
alert("This will only run after 2000 ms");
});
这是个好主意吗?
在promises规范过程中,这是一个备受争议的话题。第二个链式方法虽然没有表现出这种行为,但被讨论过,但被决定反对(在Chrome中仍然可用,但很快将被删除)。你可以了解整个辩论此行为是出于实用原因,因此您不必手动执行
用其他语言
值得一提的是,其他语言并没有做到这一点,Scala中的未来或C#中的任务都没有这一特性。例如,在C#中,您必须调用
任务。对任务展开,以等待其链解析。Promise然后返回Promise对象
,而不是Promise的解析值
。我用叉子叉了你的叉子,加了一些我的叉子
promise。然后在解析promise对象之后立即执行。请检查以下示例,了解promises
的工作原理:
The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.
console.log('person1:shoe-ticket');
控制台日志(“人员2:鞋票”);
const promiseGirlfriendBringtickets=新承诺((解决,拒绝)=>{
设置超时(()=>{
决议(“票证”);
}, 3000);
});
PromiseGirlfriendBringtickets.然后((t)=>{
log(`person3:show${t}`);
})
控制台日志(“人员4:鞋票”);
控制台日志(“人员5:鞋票”)代码>通常代码是同步的-一条语句执行就像(fileopen)一样,并且可以保证下一条语句将在之后立即执行,就像filewrite()