理解promise--一个问题引发的思考
这篇文章动机是为了解释这个问题
往下阅读之前你需要知道,promise的resolve回调函数会被放在job queue中等待主任务执行完毕后等待执行(这也是文章提到的问题的解答)。可以参考这篇文章
代码一
new Promise((resolve, reject) => { resolve(); //将resolved回调函数(then的第一个参数)添加到queue队列 }).then(() => { console.log("promise1 resolved"); }); new Promise((resolve, reject) => { resolve(); //将resolved回调函数(then的第一个参数)添加到queue队列 }).then(() => { console.log("promise3 resoved"); }); console.log('main'); //result: //main //promise1 resolved //promise3 resoved
这个结果很好理解,两个resolve()函数将两个回调函数依次添加到job queue队列,主任务队列执行完后,依次执行job queue中的任务。
代码二
在看代码前首先要理解promise then函数的返回值也是一个promise,而返回的promise的状态(pending,resolved,reject)在不同情况下会是不同的值,具体请参考MDN上的解释。为方便理解,请大家记住下面这段代码中的then函数的返回值均是处于resolved状态的promise。并请牢记一个promise如果是resolved状态则它会将其then回调函数作为一个任务添加到job queue。为方便解释,我会在代码中将每个then函数标记为一个任务,希望大家能对照着看。OK,让我们来看代码
new Promise((resolve, reject) => { resolve(); //resolve_1 }).then(() => { // then_task_1 console.log("promise1 resolved"); }).then(() => { // then_task_2 console.log("promise2 resolved"); }).then(() => { // then_task_3 console.log("promise3 resolved"); }); new Promise((resolve, reject) => { resolve(); //resolve_2 }).then(() => { // then_task_x console.log("promisex resolved"); }).then(() => { // then_task_y console.log("promisey resolved"); }).then(() => { // then_task_z console.log("promisez resolved"); }); console.log('main'); //result: //main //promise1 resolved //promisex resolved //promise2 resolved //promisey resolved //promise3 resolved //promisez resolved
1,首先resolve_1将then_task_1添加到job queue,然后resolve2将then_task_x添加到job queue。然后执行到console.log('main')。
主任务队列中的任务执行完成,主任务队列空(是的,这时job queue中只有then_task_1和then_task_x)。
2,开始执行job queue中的任务:执行then_task_1,打印promise1,这时返一个resolved promise,这个promise的then是then_task_2,js将then_task_2添加到then_task_x后;执行then_task_x,打印promisx,同理将then_task_y添加到then_task_2后。依次类推,我们就看到了代码结果这样的打印顺序。
代码三
new Promise((resolve, reject) => { resolve(Promise.resolve().then(() => { //then_task_innner console.log('inner promise resolved') })); //外层resolve对应then_task1,内层resolve对应then_task_inner }).then(() => { //then_task_1 console.log("promise1 resolved"); }); new Promise((resolve, reject) => { resolve(); //resolve2 }).then(() => { //then_task_2 console.log("promise2 resolved"); }); console.log('main'); //result: //main //inner promise resolved //promise2 resolved //promise1 resolved
这段代码执行到第一个resolve时发现其参数是一个resolved promise的then回调函数,这个参数是无法立即计算出值来的(因为这个then_task_innner被添加到job queue不会被立即执行)。所以这个resolve函数不会被立即执行。所以到这里then_task_innner被添加到job queue了,但是then_task_1并没有,因为其对应的promise还处于pending状态,没有被resolve。然后执行到resolve2,将then_task_2添加到job queue。然后执行console.log('main'),主任务队列完成。这时job queue中有then_task_inner和then_task_2。当执行完then_task_inner后,第一个resolve()会被添加到job queue,这时job queue中只有resolve()这个任务,这个resolve被执行。其对应的promise变为resolved状态,对应的then_task_1被添加到job queue中,然后被执行。因此我们看到屏幕上的打印结果是这样的。
代码四
有了代码三的铺垫,我们现在来看看下面这段代码。
new Promise((resolve, reject) => { resolve(Promise.resolve()); //为方便解释,我们将外层的resolve叫做 outer_resolve;内层的resolve叫做inner_resolve }).then(() => { //promise1_task console.log("promise1 resolved"); }); new Promise((resolve, reject) => { resolve(); //resolve2 对应 promise2_task }).then(() => { //promise2_task console.log("promise2 resolved"); }).then(() => { //promise3_task console.log("promise3 resolved"); }); console.log('main'); //result: //main //promise2 resolved //promise3 resolved //promise1 resolved
放这段代码是为了过渡,方便解释下面的问题。
这段代码对比代码三inner_resolve没有了.then();不过并不是没有了,我们可以理解为inner_resolve对应的promise的then函数是null。
程序首先运行到第一个resolve,发现无法立即获得参数值,对应的promise无法改变状态,任然是pendding,所以对应的promise1_task不会被添加到job queue。然而inner_resolve被执行了,其对应的then函数(null)被添加到job queue。接下来第二个resolve被执行,对应的promise2_task被添加到job queue。之后主任务执行完成,开始执行job queue中的任务。对一个任务是null,执行完后因为第一个resolve的参数有了,所以这个resolve函数被添加到job queue中;接下来是执行promise2_task,打印promise2 并将promise3_task添加到job queue。然后执行第一个resolve函数,其对应的promise1_task被添加到job queue。接下来是执行promise3_task,然后promise1_task。
如果我们将resolve(Promise.resolve())换成resolve()。就会看到打印结果顺序是promise1,promise2,promise3。
回到最初的问题
new Promise((resolve, reject) => { console.log("async1 start"); console.log("async2"); resolve(Promise.resolve()); //这里的Promise.resolve会添加一个null任务到job queue,外层resolve对应async1_end_task }).then(() => { //async1_end_task console.log("async1 end"); }); new Promise(function(resolve) { console.log("promise1"); resolve(); //对应promise2_task }).then(function() { //promise2_task console.log("promise2"); }).then(function() { //promise3_task console.log("promise3"); }).then(function() { //promise4_task console.log("promise4"); }); //result: //async1 start //async2 //promise1 //promise2 //promise3 //async1 end //promise4
这里我们对async1 start,async2,promise1的打印顺序不解释,这时在主任务中执行的,按主任务执行顺序打印。
romise2,promise3,async1 end,promise4的打印顺序解释同代码四