promise的一点小Tip

今天练习promise的时候,

let p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('hello')
    }, 2000)
})
console.log('1', p1)

let p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('world')
    }, 2000)
})
console.log('2', p2)

p1.then((data) => {
    console.log(data)
    return p2
})
.then((data) => {
    console.log(data)
})

输出结果:helloworld同时输出
在这里插入图片描述
在此之前,我理解的promise一直是可以保证执行顺序的,即2秒后输出hello,2秒后再输出world。然而实际hello输出后立即输出了world

实际上,是我理解的promise运行机制有一定偏差。遂仔细查看官方文档:

语法:

new Promise( function(resolve, reject) {…} /* executor */ );

参数:

executor:executor是带有 resolve 和 reject 两个参数的函数 。Promise构造函数执行时立即调用 executor 函数, resolve 和 reject 两个函数作为参数传递给executor(executor函数在Promise构造函数返回所建promise实例对象前被调用)。resolve 和 reject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)。executor 内部通常会执行一些异步操作,一旦异步操作执行完毕(可能成功/失败),要么调用resolve函数来将promise状态改成fulfilled,要么调用reject 函数将promise的状态改为rejected。如果在executor函数中抛出一个错误,那么该promise 状态为rejected。executor函数的返回值被忽略。

总结下就是说,new Promise() 时,promise对象内的executor函数是同步的,因此在返回实例化promise对象前已经执行了。只是他们各自的resolve回调函数(假设都成功)按照执行顺序执行。

用浏览器的执行机制再来理一下吧。 上图:

在这里插入图片描述

new Promise()时,同步执行内部代码,定时器触发线程进行计数,定时时间到后,定时器触发线程将resolve回调函数移入任务队列。因此在上面的代码中,实例化两个promise对象时,其内部的异步代码已经执行,2秒后两个promise内部定时器都已经定时时间到,两个resolve函数都已经在任务列表中等待,等待执行。然后浏览器执行微任务,连续输出helloworld

如果想要实现我们原先的目的,即2秒后输出hello,2秒后再输出world,就在p1的resolve回调执行后再实例化p2。即:

new Promise(resolve => {
    setTimeout(() => {
        resolve('hello')
    }, 2000)
}).then(val => {
    console.log(val) //  参数val = 'hello'
    return new Promise(resolve => {
        setTimeout(() => {
            resolve('world')
        }, 2000)
    })
}).then(val => {
    console.log(val) // 参数val = 'world'
})

又提到浏览器运行机制了,有必要自己又扩展了下:

let p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log('1')
        resolve('hello')
    }, 2000)
})

console.log('2', p1)

let p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log('3')
        resolve('world')
    }, 2000)
})

console.log('4', p2)

p1.then((data) => {
    console.log('5',data)
    return p2
})
.then((data) => {
    console.log('6',data)
})

输出:
在这里插入图片描述
运行原理:

  • 先执行同步代码,输出2,4;
  • p1实例化后,定时器触发线程同时定时两个setTimeout,但p1内的setTimeout在前,p2的setTimeout在后。于是2秒后,先输出1,此时遇到promise的reject回调(微任务),必须先执行微任务,因此输出5;
  • 此时可以执行p2的setTimeout,因此输出3,再输出6。

再修改下两个定时时间:

let p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log('1')
        resolve('hello')
    }, 3000)
})

console.log('2', p1)

let p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log('3')
        resolve('world')
    }, 2000)
})

console.log('4', p2)

p1.then((data) => {
    console.log('5',data)
    return p2
})
.then((data) => {
    console.log('6',data)
})

输出:(先输出2,4,2秒后输出3,1秒后输出1,5,6
在这里插入图片描述
因为我们是链式调用,必须得p1的回调执行完毕后才能执行p2的回调。因此输出3后,需再等一秒先等p1的setTimeout定时结束,执行p1的回调,然后才能顺序执行p2的回调。

如果我们取消链式调用呢?

let p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log('1')
        resolve('hello')
    }, 3000)
})

console.log('2', p1)

let p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log('3')
        resolve('world')
    }, 2000)
})

console.log('4', p2)

p1.then((data) => {
    console.log('5',data)
})

p2.then((data) => {
    console.log('6',data)
})

如果我们取消链式调用,则输出:
在这里插入图片描述
按照宏任务执行后,先执行对应微任务,然后继续执行宏任务的机制运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值