我对Promise在JavaScript中的行为感到困惑,并有一些疑问,有人可以帮我弄清楚吗?
这是创建Promise的两种常用方法。
function promise(){
return new Promise((resolve, reject) => {
resolve()});
}
let promise = new Promise(function(resolve, reject){
resolve();
});
第一个函数创建Promise对象,但是直到我们调用该函数时才调用它。相比之下,第二条语句创建一个Promise对象并立即调用它。我说的对吗?
此功能:
function timeout(ms){
return new Promise((resolve, reject) => {
setTimeout(resolve, ms, 'done');
});
}
timeout(100).then((value) => {
console.log(value);
});
我认为当我们调用超时函数时,它首先创建一个异步函数setTimeout
并将其推送到事件队列的末尾。所有同步事件完成后,将调用它并创建Promise对象。 Promise对象也将在其他同步事件之后被推送到事件队列的尾部。所以似乎有两个事件循环,对吗?
这两个语句相等吗?
let promise = new Promise(function(resolve, reject){
resolve();
});
let promise = Promise.resolve();
为什么输出序列如下所示?
setTimeout(function(){
console.log('3');
}, 0);
Promise.resolve().then(function(){
console.log('2');
});
console.log('1');
// 1
// 2
// 3
这是本书中的一个示例,作者解释如下:setTimeout(fn, 0)
将在下一个事件循环的开始处调用,Promise.resolve()
将在当前事件的结束处调用循环,console.log()
将立即被调用。
我对为什么在下一个事件循环开始时调用setTimeout
函数感到困惑。我认为它也是一个异步函数,将在当前事件队列的末尾推送,因此应在Promise对象之前调用。有人可以告诉我为什么我错了。
答案 0 :(得分:2)
第一个函数创建Promise对象,但是直到我们调用该函数时才调用它。相比之下,第二条语句创建一个Promise对象并立即调用它。我说的对吗?
第一个功能仅仅是一个功能。只要不调用它,就不会创建任何承诺。调用后,直接执行与您选择的执行没有太大区别。
我认为当我们调用超时函数时,它首先创建一个异步函数setTimeout
setTimeout
未创建,该函数作为内置函数存在。您可以说它叫 。
...并将其推送到事件队列的末尾。
不是函数setTimeout
本身被推入队列。这是回调(在这种情况下为resolve
),包括参数,超时时间和唯一计时器ID,该计时器ID置于活动计时器列表中。
所有同步事件结束后,将调用它并创建Promise对象。
在调用timeout
函数的过程中创建了Promise对象。
传递给new Promise
的回调通常称为 promise构造函数回调,正是在执行new Promise
的那一刻,回调也得以执行(同步),并创建了承诺。
当同步代码完成时,即当调用堆栈为空时,将首先使用微任务队列。在此阶段,这里什么都没有,因此可以验证任务队列。如果到那时活动计时器已过期,则任务队列中将有一个相应的条目。
Promise对象也将在其他同步事件之后被推送到事件队列的尾部
promise对象不会放入任何队列。在计时器到期时,排队事件将作为新任务被触发,即将调用resolve
函数,这将反过来解决承诺,这将把条目放入微任务队列中,一个每个then
回调和与await
相关的效果。在将其他任务从任务队列中拉出之前,将在同一(宏)任务中处理微任务队列。
所以似乎有两个事件循环,对吗?
至少两个;可以有更多。例如,在浏览器上下文中,可能还有另一个队列,用于与DOM元素突变有关的事件。 请参见this answer,了解一些不同的规范对此的看法。
- 这两个语句相等吗?
实际上是; Promise.resolve()
代表new Promise(r => r())
为什么输出序列如下所示?
setTimeout
包含一个任务队列,而.then
包含一个微任务队列,该微任务队列总是在处理任务队列之前被消耗;至少这是当前实施中的共识。
以下是对以下代码的事件序列的一些澄清:
function timeout(ms){
return new Promise((resolve, reject) => {
setTimeout(resolve, ms, 'done');
});
}
timeout(100).then((value) => {
console.log(value);
});
首先对代码进行解析,并创建一个任务来执行它:
timeout
(以该函数为值的提升变量)timeout
的参数为100 setTimeout
被调用。 setTimeout
的参数用于在内部计时器列表中创建一个条目。timeout
的调用者then
方法,并将其传递给函数(带有console.log
的函数)setTimeout
的函数的挂起调用,在本例中为resolve
。这种情况的确切发生方式取决于实现。
本质是,在某些时候,任务队列中有可以消耗的任务。 resolve
resolve
被称为resolve
函数)将promise标记为已解决then
回调(或await
),都应创建一个条目。
在这种情况下,只有这样一个条目:匿名函数,该匿名函数传递给了代码中唯一的then
方法。resolve
的调用)console.log
被执行console
实现产生输出任务队列中没有其他条目。系统继续检查任务队列中是否有新条目。
答案 1 :(得分:1)
答案 2 :(得分:-5)
如果您使用的是新的Promise,则意味着您正在调用一个构造函数,该构造函数将在定义数据类型和将promise定义为函数时首先执行