Promise 虽然主要是用来处理异步任务的,但我们深入理解 Promise 并不是纯为了来处理异步任务,因为在 ES7 里的 async 和 wait 能更简单的处理异步任务:
// 一个异步任务,在time毫秒后返回一个状态为reject的Promise对象
function ajax(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`完成了-${time}`)
}, time)
})
}
// 主函数
async function main() {
const ajax1 = await ajax(600)
console.log(ajax1)
const ajax2 = await ajax(500)
console.log(ajax2)
const ajax3 = await ajax(700)
console.log(ajax3)
}
main()
如上代码,在主函数前添加关键字 async ,主函数里面的每个异步任务前加上关键字 await ,并分别用一个变量接收返回值,异步任务处理便完成了。
上边代码按顺序执行:
可见,上面的3个异步任务虽然耗时各不相同,但都按照执行的先后顺序完成,并不会受耗时长短的影响。
稍加完善,正式项目中代码可能如下:
async function main() {
try {
const users = await ajax('/api/users.json')
console.log(users)
const posts = await ajax('/api/posts.json')
console.log(posts)
const urls = await ajax('/api/urls.json')
console.log(urls)
} catch (e) {
console.log(e)
}
}
async 和 wait 就是这么朴实无华,需要注意的是 await 不能单独使用,必须在 async 修饰的主函数里使用,不过 await 单独使用的提案已经提出,也许不久的将来 await 就可以单独使用了,那时将更加的方便。
宏任务和微任务
先看一段代码:
console.log('start')
setTimeout(() => {
console.log('setTimeout')
}, 0)
new Promise((resolve, reject) => {
console.log('promise')
resolve('then')
}).then(res => {
console.log(res)
})
console.log('end')
上面代码的执行顺序,估计很多人都理不对,正常的执行顺序如下:
这里涉及宏任务和微任务的概念。
new Promise() 本身和同步任务执行模式没区别,会直接执行,不会去消息队列里排队,所以在第一轮执行中,所有同步任务会按续执行,即按续打印:“start”、“promise”、“end”。
执行到 setTimeout() 的时候,会产生一个宏任务,这个宏任务会进入到消息队列中排队,等待同步任务执行完之后才会执行。
在 new Promise() 执行的时候,它后面的 then 产生一个微任务,这个微任务也会进入消息队列中排队,等待同步任务执行完之后才会执行。
同步任务执行完之后,此时消息队列中有一个宏任务和一个微任务,微任务的执行优先度比宏任务高,所以先执行微任务,再执行宏任务,所以随后先后打印:“then”、“setTimeout”。
如果你觉得理解了宏任务微任务,那么再看看下面这个代码:
new Promise((resolve, reject) => {
console.log(1)
resolve()
}).then(() => {
console.log(2)
}).then(() => {
console.log(3)
})
new Promise((resolve, reject) => {
console.log(111)
resolve()
}).then(() => {
console.log(222)
}).then(() => {
console.log(333)
})
执行试试吧,看看是否与预想的一样?
文章内容输出来源:拉勾大前端高薪训练营,以上文章中的内容根据老师讲课的语音和代码,结合自己的理解编辑完成。