Promise 中异步执行的代码在哪里?
Posted
技术标签:
【中文标题】Promise 中异步执行的代码在哪里?【英文标题】:Where is code executed asynchronously in a Promise? 【发布时间】:2017-09-20 01:48:37 【问题描述】:以下javascript函数来自You Don't Know JS: Async & Performance。据我了解,第一条评论// start doing something that could take a while
具有误导性。实际可能异步完成的代码部分位于传递给Promise 构造函数的函数中。
function foo(x)
// start doing something that could take a while *misleading comment*
// construct and return a promise
return new Promise( /* executor */ function(resolve,reject)
// eventually, call `resolve(..)` or `reject(..)`,
// which are the resolution callbacks for
// the promise.
);
我会通过以下方式修复它:
function foo(x)
// construct and return a promise
return new Promise( /* executor */ function(resolve,reject)
// start doing something that could take a while
// then foo returns the newly created Promise
// eventually, call `resolve(..)` or `reject(..)`,
// which are the resolution callbacks for
// the promise.
);
【问题讨论】:
是的,你的构造可能更好,尽管代码也可以在你创建 Promise 之前执行。我不确定你在这里问什么你还不知道答案的问题。 代码太抽象,无法真正找出错误,或者“宣称”一个比另一个更好 答案是:无处可去。 promise 执行器函数同步运行。您可以从那里启动一个异步操作,最终调用resolve
或reject
(可能使用回调)。认为 promise executor 函数本身以某种方式异步运行是一个常见的误解——这不是真的——我担心你的问题(以及确认的答案,虽然是正确的)可能会让人们误入歧途。您可以对其进行编辑以更清楚地说明这一点吗?
@jfriend00 代码可以在你创建promise之前执行,但是你必须引入一个辅助变量来调用resolve或reject,see this comment
【参考方案1】:
答案是:promise 中没有任何地方可以异步执行代码。 *
虽然您展示的第二种形式稍有优势,但这仅仅是因为它更一致地处理错误(期望调用者同时处理异常和拒绝是一种糟糕的形式)。
解决您的主要困惑:promise executor 函数同步运行。来自MDN:
executor 函数由 Promise 实现立即执行,传递 resolve 和 reject 函数(在 Promise 构造函数甚至返回创建的对象之前调用 executor)。
还有spec:
从执行器函数返回并不意味着延迟操作已经完成,而只是表示最终执行延迟操作的请求已被接受。
由您决定是否启动最终调用resolve
或reject
的任何异步操作:
new Promise(resolve => setTimeout(resolve, 2000))
.then(() => console.log("Async"));
console.log("Sync");
最重要的是,Promise 构造函数仅用于包装不支持 Promise 的遗留函数。 Don't use it for anything else.
*) 实际上,.then
保证传递给它的函数永远不会立即运行,所以我的第一句话并不完全正确。它们最快可以运行在事件循环的同一运行结束时,在微任务队列中。几乎不是你想要的。
【讨论】:
“它们可以运行的最快时间是在事件循环的同一运行结束时,在微任务队列中。”微任务队列是否与作业队列相同(如here所述)? 是的。请注意,您附加到.then
的任何函数仍然作为单线程阻塞代码运行,就像所有其他 JavaScript 一样。它只是稍后运行。真正在另一个线程上运行 JS 的唯一方法是 launch a worker。【参考方案2】:
是的,这应该解决(感谢提交this issue)。
这让我想起了difference between the deferred pattern and the revealing constructor pattern。在 promise 构造函数回调中启动异步任务有两个好处:
如果它同步抛出(例如语法错误、方法调用中的拼写错误等),异常将被隐式捕获并拒绝承诺resolve
和 reject
回调已经在范围内,可以作为回调传递给异步进程。
【讨论】:
以上是关于Promise 中异步执行的代码在哪里?的主要内容,如果未能解决你的问题,请参考以下文章
[万字详解]JavaScript 中的异步模式及 Promise 使用
对Promise中的resolve,reject,catch的理解