了解 javascript 承诺;堆栈和链接
Understanding javascript promises; stacks and chaining
我 运行 遇到了一些关于 javascript promises 的问题,尤其是关于堆叠链的问题。
任何人都可以向我解释这些不同实现之间的区别(如果有的话!)?
实施 1
var serverSidePromiseChain;
serverSidePromiseChain = async().then(function(response) {
console.log('1', response);
return response;
}).then(function(response) {
console.log('2', response);
return true;
}).then(function(response) {
console.log('3', response); // response expected to be 'true'
return async3();
}).then(function(response) {
console.log('4', response);
return async4();
})
实施 2
var serverSidePromiseChain;
serverSidePromiseChain = async().then(function(response) {
console.log('1', response);
return response;
});
serverSidePromiseChain.then(function(response) {
console.log('2', response);
return true;
})
serverSidePromiseChain.then(function(response) {
console.log('3', response); // response expected to be 'true'
return async3();
})
serverSidePromiseChain.then(function(response) {
console.log('4', response);
return async4();
})
实施 3
var serverSidePromiseChain;
serverSidePromiseChain = async().then(function(response) {
console.log('1', response);
return response;
});
serverSidePromiseChain = serverSidePromiseChain.then(function(response) {
console.log('2', response);
return true;
})
serverSidePromiseChain = serverSidePromiseChain.then(function(response) {
console.log('3', response); // response expected to be 'true'
return async3();
})
serverSidePromiseChain = serverSidePromiseChain.then(function(response) {
console.log('4', response);
return async4();
})
链的一部分 returns 值(第 2 步中的 'true')是否改变了行为?承诺是否要求所有返回值都是异步承诺以保持行为?
您正在说明链接和分支之间的区别。链接将对多个异步操作进行排序,以便一个在前一个完成时开始,您可以链接任意数量的项目以一个接一个地排序。
分支连接多个异步操作,以便在一个触发操作完成时同时进行所有操作。
实现1和3是一样的。他们被束缚着。实现 3 只是使用一个临时变量进行链接,而实现 1 只是直接使用 .then()
中的 return 值。执行没有区别。这些 .then()
处理程序将以串行方式调用。
实现 2 不同。它是分支的,而不是链式的。因为所有后续的 .then()
处理程序都附加到完全相同的 serverSidePromiseChain
promise,所以它们都只等待第一个 promise 被解决,然后所有后续的异步操作都同时进行(不是连续的)与其他两个选项一样)。
深入了解它如何与 promises 一起工作可能有助于理解这一点。
当你这样做时(场景 1 和 3):
p.then(...).then(...)
情况如下:
- 解释器获取您的
p
变量,在其上找到 .then()
方法并调用它。
.then()
方法仅存储传递给它的回调,然后 return 是一个新的 promise 对象。它此时不调用其回调。这个新的 promise 对象与原始 promise 对象及其存储的回调相关联。直到双方都满意才会解决。
- 然后调用新 returned promise 上的第二个
.then()
处理程序。同样,该承诺上的 .then()
处理程序仅存储 .then()
回调,它们尚未执行。
- 然后在将来的某个时候,原始承诺
p
会通过其自己的异步操作得到解决。解析后,它会调用它存储的任何 resolve
处理程序。其中一个处理程序将是对上述链中第一个 .then()
处理程序的回调。如果该回调运行完成并且 return 没有任何内容或静态值(例如,return 本身不是一个承诺),那么它将在之后解析它创建的 return 的承诺.then()
被第一次调用。当该承诺得到解决时,它将调用上面第二个 .then()
处理程序安装的解析处理程序,依此类推。
执行此操作时(场景 2):
p.then();
p.then();
此处的一个承诺 p
已存储来自两个 .then()
调用的解析处理程序。当最初的承诺 p
得到解决时,它将调用两个 .then()
处理程序。如果 .then()
处理程序本身包含异步代码和 return 承诺,这两个异步操作将同时进行(类似并行的行为),而不是像场景 1 和场景 3 中那样按顺序进行。
实现 1 和 3 似乎是等效的。
在实现 2 中,最后 3 个 .then()
函数都作用于相同的承诺。 .then()
方法 returns 一个新的承诺。已履行的承诺的价值无法更改。参见 Promises/A+ 2.1.2.2。您在实施 2 中的评论(预期响应为真)表明您不希望如此。不,response
不会为真(除非那是原始承诺的值)。
让我们试试吧。 运行 下面的代码片段可以看出差异:
function async(){ return Promise.resolve("async"); }
function async3(){ return Promise.resolve("async3"); }
function async4(){ return Promise.resolve("async4"); }
function implementation1() {
logContainer = document.body.appendChild(document.createElement("div"));
console.log("Implementation 1");
var serverSidePromiseChain;
serverSidePromiseChain = async().then(function(response) {
console.log('1', response);
return response;
}).then(function(response) {
console.log('2', response);
return true;
}).then(function(response) {
console.log('3', response); // response expected to be 'true'
return async3();
}).then(function(response) {
console.log('4', response);
return async4();
});
}
function implementation2() {
logContainer = document.body.appendChild(document.createElement("div"));
console.log("Implementation 2");
var serverSidePromiseChain;
serverSidePromiseChain = async().then(function(response) {
console.log('1', response);
return response;
});
serverSidePromiseChain.then(function(response) {
console.log('2', response);
return true;
});
serverSidePromiseChain.then(function(response) {
console.log('3', response); // response expected to be 'true'
return async3();
});
serverSidePromiseChain.then(function(response) {
console.log('4', response);
return async4();
});
}
function implementation3() {
logContainer = document.body.appendChild(document.createElement("div"));
console.log("Implementation 3");
var serverSidePromiseChain;
serverSidePromiseChain = async().then(function(response) {
console.log('1', response);
return response;
});
serverSidePromiseChain = serverSidePromiseChain.then(function(response) {
console.log('2', response);
return true;
});
serverSidePromiseChain = serverSidePromiseChain.then(function(response) {
console.log('3', response); // response expected to be 'true'
return async3();
});
serverSidePromiseChain = serverSidePromiseChain.then(function(response) {
console.log('4', response);
return async4();
});
}
var logContainer;
var console = {
log: function() {
logContainer.appendChild(document.createElement("div")).textContent = [].join.call(arguments, ", ");
}
};
onload = function(){
implementation1();
setTimeout(implementation2, 10);
setTimeout(implementation3, 20);
}
body > div {
float: left;
font-family: sans-serif;
border: 1px solid #ddd;
margin: 4px;
padding: 4px;
border-radius: 2px;
}
实现#1 和#3 是等效的。实施 #2 不同,因为那里没有链,所有回调都将在同一个承诺上执行。
现在让我们稍微讨论一下 promise 链。 specs 表示:
2.2.7 then
must return a promise
2.2.7.1 If either onFulfilled
or onRejected
returns a value x
, run the Promise Resolution Procedure [[Resolve]](promise2, x)
2.3.3 If x
is a promise, adopt its state
基本上是根据 return 的承诺调用 then
另一个 promise
,它根据 callback return value
得到 resolved/rejected。在您的情况下,您正在 returning 标量值,然后将其沿着链传播到下一个承诺。
在您的特定情况下,会发生以下情况:
- #1:你有 7 个承诺(
async
调用加上 4 个 then
,加上来自 async3()
/async4
的两个),serverSidePromiseChain
将指向 then
编辑的最后一个承诺 return。现在,如果 async()
所承诺的 return 永远不会 resolved/rejected,那么 serverSidePromiseChain
也会处于相同的情况。与 async3()
/async4()
相同,如果该承诺也不是 resolved/rejected
- #2:
then
在同一个承诺上被多次调用,创建了额外的承诺,但它们不会影响应用程序的流程。一旦 return 由 async()
编辑的承诺将被解决,所有回调将被执行,回调 return 将被丢弃
- #3:这等同于#1,只是现在你显式地传递了创建的承诺。当承诺 returned
async()
得到解决时,第一个回调将被执行,它用 true
解决下一个承诺,第二个回调将相同,第三个将具有如果 async3()
的承诺被拒绝,则有机会将链转换为失败的链,与 returns async4()
的承诺的回调相同。
Promise 链最适合实际的异步操作,操作依赖于前一个操作的结果,你不想写很多胶水代码,你也不想达到callback hell.
我在我的博客上写了一系列关于 promises 的文章,其中一篇描述了 promises 的链接特性可以找到 here;这篇文章是针对ObjectiveC的,但是原理是一样的。
我 运行 遇到了一些关于 javascript promises 的问题,尤其是关于堆叠链的问题。
任何人都可以向我解释这些不同实现之间的区别(如果有的话!)?
实施 1
var serverSidePromiseChain;
serverSidePromiseChain = async().then(function(response) {
console.log('1', response);
return response;
}).then(function(response) {
console.log('2', response);
return true;
}).then(function(response) {
console.log('3', response); // response expected to be 'true'
return async3();
}).then(function(response) {
console.log('4', response);
return async4();
})
实施 2
var serverSidePromiseChain;
serverSidePromiseChain = async().then(function(response) {
console.log('1', response);
return response;
});
serverSidePromiseChain.then(function(response) {
console.log('2', response);
return true;
})
serverSidePromiseChain.then(function(response) {
console.log('3', response); // response expected to be 'true'
return async3();
})
serverSidePromiseChain.then(function(response) {
console.log('4', response);
return async4();
})
实施 3
var serverSidePromiseChain;
serverSidePromiseChain = async().then(function(response) {
console.log('1', response);
return response;
});
serverSidePromiseChain = serverSidePromiseChain.then(function(response) {
console.log('2', response);
return true;
})
serverSidePromiseChain = serverSidePromiseChain.then(function(response) {
console.log('3', response); // response expected to be 'true'
return async3();
})
serverSidePromiseChain = serverSidePromiseChain.then(function(response) {
console.log('4', response);
return async4();
})
链的一部分 returns 值(第 2 步中的 'true')是否改变了行为?承诺是否要求所有返回值都是异步承诺以保持行为?
您正在说明链接和分支之间的区别。链接将对多个异步操作进行排序,以便一个在前一个完成时开始,您可以链接任意数量的项目以一个接一个地排序。
分支连接多个异步操作,以便在一个触发操作完成时同时进行所有操作。
实现1和3是一样的。他们被束缚着。实现 3 只是使用一个临时变量进行链接,而实现 1 只是直接使用 .then()
中的 return 值。执行没有区别。这些 .then()
处理程序将以串行方式调用。
实现 2 不同。它是分支的,而不是链式的。因为所有后续的 .then()
处理程序都附加到完全相同的 serverSidePromiseChain
promise,所以它们都只等待第一个 promise 被解决,然后所有后续的异步操作都同时进行(不是连续的)与其他两个选项一样)。
深入了解它如何与 promises 一起工作可能有助于理解这一点。
当你这样做时(场景 1 和 3):
p.then(...).then(...)
情况如下:
- 解释器获取您的
p
变量,在其上找到.then()
方法并调用它。 .then()
方法仅存储传递给它的回调,然后 return 是一个新的 promise 对象。它此时不调用其回调。这个新的 promise 对象与原始 promise 对象及其存储的回调相关联。直到双方都满意才会解决。- 然后调用新 returned promise 上的第二个
.then()
处理程序。同样,该承诺上的.then()
处理程序仅存储.then()
回调,它们尚未执行。 - 然后在将来的某个时候,原始承诺
p
会通过其自己的异步操作得到解决。解析后,它会调用它存储的任何resolve
处理程序。其中一个处理程序将是对上述链中第一个.then()
处理程序的回调。如果该回调运行完成并且 return 没有任何内容或静态值(例如,return 本身不是一个承诺),那么它将在之后解析它创建的 return 的承诺.then()
被第一次调用。当该承诺得到解决时,它将调用上面第二个.then()
处理程序安装的解析处理程序,依此类推。
执行此操作时(场景 2):
p.then();
p.then();
此处的一个承诺 p
已存储来自两个 .then()
调用的解析处理程序。当最初的承诺 p
得到解决时,它将调用两个 .then()
处理程序。如果 .then()
处理程序本身包含异步代码和 return 承诺,这两个异步操作将同时进行(类似并行的行为),而不是像场景 1 和场景 3 中那样按顺序进行。
实现 1 和 3 似乎是等效的。
在实现 2 中,最后 3 个 .then()
函数都作用于相同的承诺。 .then()
方法 returns 一个新的承诺。已履行的承诺的价值无法更改。参见 Promises/A+ 2.1.2.2。您在实施 2 中的评论(预期响应为真)表明您不希望如此。不,response
不会为真(除非那是原始承诺的值)。
让我们试试吧。 运行 下面的代码片段可以看出差异:
function async(){ return Promise.resolve("async"); }
function async3(){ return Promise.resolve("async3"); }
function async4(){ return Promise.resolve("async4"); }
function implementation1() {
logContainer = document.body.appendChild(document.createElement("div"));
console.log("Implementation 1");
var serverSidePromiseChain;
serverSidePromiseChain = async().then(function(response) {
console.log('1', response);
return response;
}).then(function(response) {
console.log('2', response);
return true;
}).then(function(response) {
console.log('3', response); // response expected to be 'true'
return async3();
}).then(function(response) {
console.log('4', response);
return async4();
});
}
function implementation2() {
logContainer = document.body.appendChild(document.createElement("div"));
console.log("Implementation 2");
var serverSidePromiseChain;
serverSidePromiseChain = async().then(function(response) {
console.log('1', response);
return response;
});
serverSidePromiseChain.then(function(response) {
console.log('2', response);
return true;
});
serverSidePromiseChain.then(function(response) {
console.log('3', response); // response expected to be 'true'
return async3();
});
serverSidePromiseChain.then(function(response) {
console.log('4', response);
return async4();
});
}
function implementation3() {
logContainer = document.body.appendChild(document.createElement("div"));
console.log("Implementation 3");
var serverSidePromiseChain;
serverSidePromiseChain = async().then(function(response) {
console.log('1', response);
return response;
});
serverSidePromiseChain = serverSidePromiseChain.then(function(response) {
console.log('2', response);
return true;
});
serverSidePromiseChain = serverSidePromiseChain.then(function(response) {
console.log('3', response); // response expected to be 'true'
return async3();
});
serverSidePromiseChain = serverSidePromiseChain.then(function(response) {
console.log('4', response);
return async4();
});
}
var logContainer;
var console = {
log: function() {
logContainer.appendChild(document.createElement("div")).textContent = [].join.call(arguments, ", ");
}
};
onload = function(){
implementation1();
setTimeout(implementation2, 10);
setTimeout(implementation3, 20);
}
body > div {
float: left;
font-family: sans-serif;
border: 1px solid #ddd;
margin: 4px;
padding: 4px;
border-radius: 2px;
}
实现#1 和#3 是等效的。实施 #2 不同,因为那里没有链,所有回调都将在同一个承诺上执行。
现在让我们稍微讨论一下 promise 链。 specs 表示:
2.2.7
then
must return a promise
2.2.7.1 If eitheronFulfilled
oronRejected
returns a valuex
, run the Promise Resolution Procedure[[Resolve]](promise2, x)
2.3.3 Ifx
is a promise, adopt its state
基本上是根据 return 的承诺调用 then
另一个 promise
,它根据 callback return value
得到 resolved/rejected。在您的情况下,您正在 returning 标量值,然后将其沿着链传播到下一个承诺。
在您的特定情况下,会发生以下情况:
- #1:你有 7 个承诺(
async
调用加上 4 个then
,加上来自async3()
/async4
的两个),serverSidePromiseChain
将指向then
编辑的最后一个承诺 return。现在,如果async()
所承诺的 return 永远不会 resolved/rejected,那么serverSidePromiseChain
也会处于相同的情况。与async3()
/async4()
相同,如果该承诺也不是 resolved/rejected - #2:
then
在同一个承诺上被多次调用,创建了额外的承诺,但它们不会影响应用程序的流程。一旦 return 由async()
编辑的承诺将被解决,所有回调将被执行,回调 return 将被丢弃 - #3:这等同于#1,只是现在你显式地传递了创建的承诺。当承诺 returned
async()
得到解决时,第一个回调将被执行,它用true
解决下一个承诺,第二个回调将相同,第三个将具有如果async3()
的承诺被拒绝,则有机会将链转换为失败的链,与 returnsasync4()
的承诺的回调相同。
Promise 链最适合实际的异步操作,操作依赖于前一个操作的结果,你不想写很多胶水代码,你也不想达到callback hell.
我在我的博客上写了一系列关于 promises 的文章,其中一篇描述了 promises 的链接特性可以找到 here;这篇文章是针对ObjectiveC的,但是原理是一样的。