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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 13:39:17  来源:igfitidea点击:

Why does the Promise constructor require a function that calls 'resolve' when complete, but 'then' does not - it returns a value instead?

javascriptpromiseecmascript-6es6-promise

提问by Dan Nissenbaum

As I plunge into studying Promises, my understanding has halted on the following question that I do not find discussed (all I find are specific discussions of the Promiseconstructor, and the Promise'then' function - but not a discussion that compares their design patterns).

当我开始研究Promises 时,我的理解停止在以下我没有讨论过的问题上(我发现的只是对Promise构造函数和Promisethen”函数的具体讨论- 但不是比较它们的设计模式的讨论)。



1. The Promiseconstructor

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 resolveand reject. The first argument fulfills the promise, the second argument rejects it. We can call these functions, once our operation is completed.

带有两个参数的函数对象resolvereject。第一个参数实现了承诺,第二个参数拒绝了它。一旦我们的操作完成,我们就可以调用这些函数。



2. The thenfunction

2.then功能

Moving on to the thenfunctionthat can be called on a Promiseobject (which returns a new Promiseobject), 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 thenmethod 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 resolvefunction in Stage 1(in the second occurrence of resolve- beneath (2), above) is passed on to the next stage (the first thenfunction 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 thenfunction).

从上面的代码片段中,我似乎很清楚在阶段 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 thenfunction 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 Promiseconstructor utilizes a different design pattern than the thenfunction?

或者我是否缺少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()将对承诺的状态做出反应

Diagram: Promise() executor vs. then() method(Code examples adapted from Jake Archibald's classic tutorial.)

图:Promise() 执行器与 then() 方法(代码示例改编自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 Promiseconstructor 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 Promiseconstructor and the thenmethod because they are two independent things, designed for different purposes.

Promise构造函数和then方法之间没有对应关系,因为它们是两个独立的东西,为不同的目的而设计。

The Promiseconstructor is only used for promisifying1asynchronous functions. Indeed, as you say, it is built on invokingresolve/rejectcallbacks to asynchronously sendvalues, and there are no return values in that case.

Promise构造仅用于promisifying 1个异步函数。事实上,正如你所说,它是建立在调用resolve/reject回调异步发送值的基础上的,在这种情况下没有返回值。

That the Promiseconstructor itself does take this "resolver" callback (to which it synchronously passes resolveand reject) is in fact an enhancement of the older deferred pattern, and bears no intended similarityto the thencallbacks.

Promise构造本身并借此“解析”回调(与它同步传递resolvereject)实际上是上了年纪的增强递延模式,并承担不打算相似then回调。

var p = new Promise(function(res, rej) {    |    var def = Promise.Deferred();
    setTimeout(res, 100);                   |    setTimeout(def.resolve, 100);
});                                         |    var p = def.promise;

The thencallbacks in contrast are classical asynchronous callbacks, with the additional featurethat you can returnfrom them. They are being invoked asynchronouslyto receivevalues.

then相比之下,回调是经典的异步回调,具有您可以从中获得的附加功能return。它们被异步调用接收值。

p.then(function(val) { … });

To sum up the differences:

总结一下差异:

  • Promiseis a constructor, while thenis a method
  • Promisetakes one callback, while thentakes up to two
  • Promiseinvokes its callback synchronously, while theninvokes its callbacks asynchronously
  • Promisealways invokes its callback,
    thenmight not invoke its callbacks (if the promise is not fulfilled/rejected)
  • Promisepasses the capabilities to resolve/reject a promise to the callback,
    thenpasses the result value / rejection reason of the promise it was called on
  • Promiseinvokes its callback for the purpose of executing side effects (call reject/resolve),
    theninvokes 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 Promiseconstructor provides, though that's not their primary purpose. thenbasically offers the ability to attach onFulfilled/onRejectedcallbacks to an existing promise, which is rather diametral to the Promiseconstructor.

是的,两者都返回承诺,尽管它们与许多其他函数(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 resolveand rejectarguments 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 resolvewith success response and rejectwith 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 fun1and fun2are plain old javascript functions (they just happen to take the future outcome of your async operation as arguments), they returnvalues (which can be undefinedif you don't explicitly return).

Promise 构造函数中的resolvereject参数不是您定义的函数。将它们视为您可以嵌入到异步操作代码中的钩子(通常您resolve有成功响应和reject失败原因),以便 javascript 有办法最终根据异步操作的结果将 Promise 标记为已完成或已拒绝; 一旦发生这种情况,您在其中定义的适当函数将then(fun1, fun2)被触发以使用 Promise(fun1(success_response)或者fun2(failure_reason),取决于 Promise 是否已实现/拒绝)。由于fun1fun2是普通的旧 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