resolve
的实际作用是什么?
考虑下面的代码。
打印:1 3 4 5 6 9 7 10 11 2.
不管resolve
写在什么地方,它都打印相同的内容!
有人可以解释为什么会这样吗?
new Promise((resolve, reject) => {
console.log(1);
setTimeout(() => {
console.log(2);
}, 0);
resolve();
new Promise((resolve, reject) => {
console.log(3);
resolve();
})
.then(() => {
console.log(4);
})
.then(() => {
console.log(9);
})
.then(() => {
console.log(10);
})
.then(() => {
console.log(11);
})
;
// resolve()
}).then(() => {
console.log(5);
new Promise((resolve, reject) => {
console.log(6);
resolve();
}).then(() => {
console.log(7);
});
})
答案 0 :(得分:3)
“解决”实际上是做什么的?
呼叫resolve(x)
有三件事。
它更改了兑现承诺的内部状态。一旦状态更改为实现,就无法再次更改状态。这是一种单向的,永久的改变。
它将值x
(无论传递给解析的单个参数)设置为promise的已解析值(此值存储在promise内部)。如果没有任何内容传递给resolve()
,则解析的值为undefined
。
它将事件插入到事件队列中,以触发当前承诺的.then()
处理程序在事件循环中即将到来的周期中被调用。这样可以安排.then()
处理程序在当前Javascript执行线程完成后运行。
现在,解释一下您在控制台中看到的顺序。首先,一些有助于理解这一点的东西。
new Promise(fn)
的回调)被同步调用(在当前执行线程中间)。setTimeout()
计时器(在JS引擎内部)触发时,计时器回调将插入事件队列中,并将在以后的事件循环中获取。.then()
或.catch()
处理程序的处理顺序是:它们最初以FIFO为基础被触发(彼此相对)(先入先出) fn().then(f1).then(f2).then(f3)
之类的诺言链时,请记住,每个.then()
都会返回一个新的诺言,该诺言将有自己的时间被解决或拒绝,取决于它之前或之后的时间,具体取决于什么发生在其处理函数中。因此,这是代码中的事件顺序:
1
0
。很快,某个计时器回调事件将添加到事件队列中。resolve()
。这会将事件/任务插入promise队列,以在事件循环的未来周期调用其.then()
处理程序。此序列Javascript代码的其余部分将继续执行。但是,请注意,由于其链式.then()
方法尚未执行,因此第一个承诺还没有任何.then()
处理程序。3
。resolve()
。这会将事件/任务插入promise队列,以在事件循环的未来周期调用其.then()
处理程序。此序列Javascript代码的其余部分将继续执行。.then()
。这会在第二个诺言中注册一个.then()
处理程序回调函数(将其添加到内部列表中)并返回一个新的诺言。.then()
。这会在第三个承诺中注册一个.then()
处理程序回调函数(将其添加到内部列表中)并返回一个新的承诺。.then()
。这会在第四个承诺中注册一个.then()
处理程序回调函数(将其添加到内部列表中)并返回一个新的承诺。.then()
。这会在第五个诺言中注册一个.then()
处理程序回调函数(将其添加到内部列表中)并返回一个新的诺言。.then()
在第一个承诺中被调用。这会在第一个诺言中注册一个.then()
处理程序回调函数(将其添加到内部列表中)并返回一个新的诺言。.then()
处理程序在第一个诺言中的.then()
处理程序之前运行,因此它将首先放入任务队列中,因此接下来将得到输出4
。 .then()
处理程序运行时,它将解析它先前创建的承诺,第三个承诺,并将一个任务添加到承诺队列中以运行其.then()
处理程序。.then()
处理程序,因此它有机会运行,您会看到输出5
。 new Promise(...)
创建另一个新的Promise,并运行其executor函数。这将导致显示输出6
。resolve()
解决。.then()
,它注册一个.then()
回调并返回新的Promise。.then()
处理程序,因此它被从事件队列中拉出,您将看到输出9
。 .then()
处理程序可以解决第五个诺言,并将其.then()
处理程序插入到诺言任务队列中。.then()
获得了new Promise().then()
处理程序,并得到了输出7
。11
,然后是12
。setTimeout()
事件并调用其回调,最后得到输出{{ 1}}。因此,2
由于一些原因而排在最后。
还有其他一些评论:
有时可以找出不同且独立的promise链中各种setTimeout()
处理程序的相对触发顺序(这仅在这里是可能的,因为没有真正的异步promise解析时间不确定),但是如果您确实需要特定的执行顺序,那么最好将您的操作链接在一起,以明确指定您希望事情在代码中运行的顺序。这消除了对本地Javascript引擎的详细实现细节的任何依赖,并使代码更具解释性。换句话说,阅读您的代码的人不必执行我列出的22个步骤即可遵循所需的执行顺序。取而代之的是,代码将仅通过直接的Promise链接指定顺序。
在真实代码中,在.then()
处理程序中创建孤立的,断开连接的Promise链是不寻常的。因为您没有从.then()
处理程序中返回那些承诺,而是将它们插入到父承诺链中,所以无法从那些断开的承诺链中传达结果或错误。尽管偶尔有理由编写无需与外界进行通信的即发即弃操作,但这是不寻常的,通常是问题代码的标志,该代码无法正确传播错误,并且结果无法与其余所有操作正确同步。
当我将'resolve'放在后面时,它会打印出相同的内容!
正如您所发现的,这并没有真正改变任何东西。直到执行程序函数完成运行并返回之后,.then()
之后的.then()
才执行,因此您在执行程序中调用new Promise(...)
的位置并不重要。换句话说,resolve()
处理程序中的任何一个甚至都无法注册,直到promise执行者返回之后,因此无论您在promise执行者中调用.then()
的位置如何,结果都是相同的。
答案 1 :(得分:2)
resolve
表示asynchronous task
的完成。
在下面的代码中,
new Promise((resolve, reject) => {
console.log(1);
setTimeout(() => {
console.log(2);
}, 0);
resolve();
new Promise((resolve, reject) => {
console.log(3);
resolve();
})
.then(() => {
console.log(4);
})
您已经创建了new Promise
,并立即使用resolve()
对其进行了解决,因此它不会等待setTimeout
被执行。 resolve();
之后紧跟着
new Promise
,创建新的Promise,然后执行立即的then
部分。
在.then
中,您没有退回任何东西,因此then
的链接不正确。返回then
中的值以正确链接它。
new Promise((resolve) => {
console.log("1");
setTimeout(() => {
resolve(2);
});
}).then((val) => {
console.log(val);
return "3";
}).then((val) => {
console.log(val);
return "4";
}).then((val) => {
console.log(val);
});