javascript 为什么 Promise 构造函数需要一个在完成时调用“resolve”的函数,而“then”不需要——而是返回一个值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31324110/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does the Promise constructor require a function that calls 'resolve' when complete, but 'then' does not - it returns a value instead?
提问by Dan Nissenbaum
As I plunge into studying Promise
s, my understanding has halted on the following question that I do not find discussed (all I find are specific discussions of the Promise
constructor, and the Promise
'then
' function - but not a discussion that compares their design patterns).
当我开始研究Promise
s 时,我的理解停止在以下我没有讨论过的问题上(我发现的只是对Promise
构造函数和Promise
“ then
”函数的具体讨论- 但不是比较它们的设计模式的讨论)。
1. The Promise
constructor
1.Promise
构造函数
From the MDN documentation, we have this use of the Promise constructor(with my comment added):
从 MDN 文档中,我们使用了 Promise 构造函数(添加了我的评论):
new Promise(function(resolve, reject) { ... }); // <-- Call this Stage 1
Function object with two arguments
resolve
andreject
. The first argument fulfills the promise, the second argument rejects it. We can call these functions, once our operation is completed.
带有两个参数的函数对象
resolve
和reject
。第一个参数实现了承诺,第二个参数拒绝了它。一旦我们的操作完成,我们就可以调用这些函数。
2. The then
function
2.then
功能
Moving on to the then
functionthat can be called on a Promise
object (which returns a new Promise
object), we have the following function signature as described by the documentation(with my comments added):
:
移动到then
功能,可以在一个被称为Promise
对象(返回一个新的Promise
对象),我们有由文档中描述的以下函数签名(加上我的意见):
p.then(onFulfilled, onRejected);
Chaining
Because the
then
method returns a Promise, you can easily chain then calls.
链接
因为该
then
方法返回一个 Promise,所以您可以轻松地链接 then 调用。
var p2 = new Promise(function(resolve, reject) {
resolve(1); // <-- Stage 1 again
});
p2.then(function(value) {
console.log(value); // 1
return value + 1; // <-- Call this Stage 2
}).then(function(value) {
console.log(value); // 2
});
My question
我的问题
From the above code snippet, it seems clear to me that the value passed to the resolve
function in Stage 1(in the second occurrence of resolve
- beneath (2), above) is passed on to the next stage (the first then
function that follows in the same code snippet). There is no return value at Stage 1.However, it is the return valueat Stage 2 that is passed on to the next stage after that (the second then
function).
从上面的代码片段中,我似乎很清楚在阶段 1 中传递给resolve
函数的值(在第二次出现resolve
- 在上面的 (2) 之下)被传递到下一个阶段(then
在相同的代码片段)。 第 1 阶段没有返回值。但是,传递到下一个阶段(第二个函数)的是第 2 阶段的返回值then
。
Is this lack of correspondence between the design pattern for the creation of a Promise
, and the use of the then
function on an existing promise (which also returns a Promise
), just a historical fluke (one requires calling a callback but returns nothing, and the other returns a value but does not call a callback)?
这是在创建 a 的设计模式Promise
与在then
现有承诺(也返回 a Promise
)上使用该函数之间缺乏对应关系,只是历史上的侥幸(一个需要调用回调但不返回任何内容,另一个返回一个值但不调用回调)?
Or am I missing an underlying reason why the Promise
constructor utilizes a different design pattern than the then
function?
或者我是否缺少Promise
构造函数使用与then
函数不同的设计模式的根本原因?
采纳答案by LarsH
Bergi's answeris excellent, and has been very helpful to me. This answer is complementary to his. In order to visualize the relationship between the Promise()
constructor and the then()
method, I created this diagram. I hope it helps somebody... maybe even me, a few months months from now.
贝尔吉的回答非常好,对我很有帮助。这个答案是对他的补充。为了可视化Promise()
构造函数和then()
方法之间的关系,我创建了这个图。我希望它可以帮助某人......甚至是我,几个月后。
The main idea here is that the "executor" function passed to the Promise()
constructor sets tasks in motion that will set the stateof the promise; whereas the handlers you pass to then()
will react to the stateof the promise.
这里的主要思想是传递给Promise()
构造函数的“执行器”函数设置了将设置承诺状态的任务;而您传递给的处理程序then()
将对承诺的状态做出反应。
(Code examples adapted from Jake Archibald's classic tutorial.)
(代码示例改编自Jake Archibald 的经典教程。)
This is a highly simplified view of how things work, leaving out many important details. But I think if one can keep a grip on a good overview of the intended purpose, it will help avoid confusion when one gets into the details.
这是对事物如何运作的高度简化的视图,省略了许多重要的细节。但我认为,如果人们能够对预期目的有一个很好的概述,那么在深入了解细节时将有助于避免混淆。
A couple of selected details
几个选定的细节
The executor is called immediately
立即调用执行程序
One important detail is that the executor function passed to the Promise()
constructor is called immediately(before the constructor returns the promise); whereas the handler functions passed to the then()
method will not be called till later(if ever).
一个重要的细节是,传递给Promise()
构造函数的 executor 函数会被立即调用(在构造函数返回 promise 之前);而传递给该then()
方法的处理程序函数将在稍后(如果有的话)才会被调用。
Bergi mentioned this, but I wanted to restate it without using the terms a/synchronously, which can be confused if you're not reading carefully: The distinction between a function callingsomething asynchronously vs. being calledasynchronously is easy to gloss over in communication.
BERGI提到这一点,但我想再说一遍,而不使用术语A /同步,可如果你不仔细阅读混淆:函数之间的区别调用一些与异步调用异步很容易在通信粉饰.
resolve()
is not onFulfill()
resolve()
不是 onFulfill()
One more detail I'd like to emphasize, because it confused me for a while, is that the resolve()
and reject()
callbacks passed to the Promise()
constructor's executor function are notthe callbacks later passed to the then()
method. This seems obvious in retrospect, but the apparent connection had me spinning in circles for too long. There is definitely a connection, but it's a loose, dynamic one.
我想强调的另一个细节,因为它让我困惑了一段时间,是传递给构造函数的执行器函数的resolve()
和reject()
回调不是后来传递给方法的回调。回想起来,这似乎很明显,但这种明显的联系让我在圈子里转了太久。肯定有联系,但它是一种松散的、动态的。Promise()
then()
Instead, the resolve()
and reject()
callbacks are functions supplied by the "system", and are passed to the executor function by the Promise
constructor when you create a promise. When the resolve()
function is called, system code is executed that potentially changes the state of the promise and eventually leads to an onFulfilled()
callback being called asynchronously. Don't think of calling resolve()
as being a tight wrapper for calling onFulfill()
!
相反,resolve()
和reject()
回调是由“系统”提供的函数,并Promise
在您创建承诺时由构造函数传递给执行程序函数。当resolve()
函数被调用时,系统代码会被执行,这可能会改变承诺的状态并最终导致onFulfilled()
回调被异步调用。不要认为 callresolve()
是call的紧密包装onFulfill()
!
回答by Bergi
There is no correspondence between the Promise
constructor and the then
method because they are two independent things, designed for different purposes.
Promise
构造函数和then
方法之间没有对应关系,因为它们是两个独立的东西,为不同的目的而设计。
The Promise
constructor is only used for promisifying1asynchronous functions. Indeed, as you say, it is built on invokingresolve
/reject
callbacks to asynchronously sendvalues, and there are no return values in that case.
该Promise
构造仅用于promisifying 1个异步函数。事实上,正如你所说,它是建立在调用resolve
/reject
回调异步发送值的基础上的,在这种情况下没有返回值。
That the Promise
constructor itself does take this "resolver" callback (to which it synchronously passes resolve
and reject
) is in fact an enhancement of the older deferred pattern, and bears no intended similarityto the then
callbacks.
该Promise
构造本身并借此“解析”回调(与它同步传递resolve
和reject
)实际上是上了年纪的增强递延模式,并承担不打算相似的then
回调。
var p = new Promise(function(res, rej) { | var def = Promise.Deferred();
setTimeout(res, 100); | setTimeout(def.resolve, 100);
}); | var p = def.promise;
The then
callbacks in contrast are classical asynchronous callbacks, with the additional featurethat you can return
from them. They are being invoked asynchronouslyto receivevalues.
then
相比之下,回调是经典的异步回调,具有您可以从中获得的附加功能return
。它们被异步调用以接收值。
p.then(function(val) { … });
To sum up the differences:
总结一下差异:
Promise
is a constructor, whilethen
is a methodPromise
takes one callback, whilethen
takes up to twoPromise
invokes its callback synchronously, whilethen
invokes its callbacks asynchronouslyPromise
always invokes its callback,then
might not invoke its callbacks (if the promise is not fulfilled/rejected)Promise
passes the capabilities to resolve/reject a promise to the callback,then
passes the result value / rejection reason of the promise it was called onPromise
invokes its callback for the purpose of executing side effects (callreject
/resolve
),then
invokes its callbacks for their result values (for chaining)
Promise
是构造函数,whilethen
是方法Promise
需要一个回调,而then
最多需要两个Promise
同步调用它的回调,同时then
异步调用它的回调Promise
总是调用它的回调,then
可能不会调用它的回调(如果承诺没有实现/拒绝)Promise
将解析/拒绝承诺的功能传递给回调,then
传递调用它的承诺的结果值/拒绝原因Promise
调用其回调以执行副作用(调用reject
/resolve
),then
调用其结果值的回调(用于链接)
Yes, both do return promises, though they share that trait with many other functions (Promise.resolve
, Promise.reject
, fetch
, …). In fact all of these are based on the same promise construction and resolve/reject capabilities that also the Promise
constructor provides, though that's not their primary purpose. then
basically offers the ability to attach onFulfilled
/onRejected
callbacks to an existing promise, which is rather diametral to the Promise
constructor.
是的,两者都返回承诺,尽管它们与许多其他函数(Promise.resolve
, Promise.reject
, fetch
, ...)共享该特性。事实上,所有这些都基于构造Promise
函数提供的相同的承诺构造和解析/拒绝功能,尽管这不是它们的主要目的。then
基本上提供了将onFulfilled
/onRejected
回调附加到现有承诺的能力,这与Promise
构造函数相当。
That both utilise callbacks is just coincidential - not a historical fluke, but rather coadaption of a language feature.
两者都使用回调只是巧合 - 不是历史上的侥幸,而是语言功能的共同适应。
1: Ideally, you would never need this because all natively asynchronous APIs return promises
1:理想情况下,您永远不需要它,因为所有本机异步 API 都返回承诺
回答by jib
The whole point of the promise constructor executor function is to disseminate resolve and reject functions to non-promise-using code, to wrap it and convert it to use a promise. If you wanted to limit this to synchronous functions only, then yes, a return value from the function could have been used instead, but that would have been silly since the useful part is to disseminate the resolver and reject functions to code that actually runs later (way after the return), e.g. to callbacks passed in to some asynchronous API.
承诺构造函数执行器函数的全部意义在于将解析和拒绝函数传播到非承诺使用代码,包装它并将其转换为使用承诺。如果您只想将其限制为同步函数,那么是的,可以使用函数的返回值来代替,但这会很愚蠢,因为有用的部分是将解析器和拒绝函数传播到稍后实际运行的代码中(返回之后的方式),例如传递给某些异步 API 的回调。
回答by Yibo Yang
Inspired by the previous answers (I'll address the part that was most confusing to me):
受先前答案的启发(我将解决最令我困惑的部分):
The resolve
and reject
arguments in the Promise constructor are not functions you define. Think of them as hooks that you get to embed into your async operation code (usually you resolve
with success response and reject
with failure reason) , so that javascript has a way to eventually mark the Promise as Fulfilled or Rejected depending on the outcome of your async operation; once that happens, the appropriate function you defined in then(fun1, fun2)
is triggered to consume the Promise (either fun1(success_response)
or fun2(failure_reason)
, depending on whether the Promise is Fulfilled/Rejected). Since fun1
and fun2
are plain old javascript functions (they just happen to take the future outcome of your async operation as arguments), they return
values (which can be undefined
if you don't explicitly return).
Promise 构造函数中的resolve
和reject
参数不是您定义的函数。将它们视为您可以嵌入到异步操作代码中的钩子(通常您resolve
有成功响应和reject
失败原因),以便 javascript 有办法最终根据异步操作的结果将 Promise 标记为已完成或已拒绝; 一旦发生这种情况,您在其中定义的适当函数将then(fun1, fun2)
被触发以使用 Promise(fun1(success_response)
或者fun2(failure_reason)
,取决于 Promise 是否已实现/拒绝)。由于fun1
和fun2
是普通的旧 javascript 函数(它们恰好将异步操作的未来结果作为参数),因此它们的return
值(可以是undefined
如果您没有明确返回)。
Also see great articles by Mozilla:
另请参阅 Mozilla 的精彩文章:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise