js是单线程脚本语言,与异步相辅相成。
同步/异步
同步任务:js中大多数都是同步任务,如script脚本、promise中的任务等。同步任务是顺序执行,会阻塞主进程。
异步任务:promise.then()函数、async/await、setTimeout、setInterval、事件绑定、图片加载、ajax请求等。异步任务不会阻塞主进程,待主进程中的任务执行完之后,会从异步任务队列中取出任务放到主线程中执行。
宏任务/微任务
宏任务:setTimeout、setInterval
微任务:promise、async/await、
先微后宏(先执行微任务队列中的所有任务,再执行一次宏任务,如此往复。)
注:
1. 遇到promise则立即执行(相当于同步),而promise.then()会被当成微任务,放入micro queue中。
2. async方法中,await前的任务是同步的,await之后的是异步的,会被当成微任务挂载起来。
例:
1. promise
new Promise(function(resolve){
// 立即执行 会在主线程中顺序执行
console.log('promise1');
resolve()
}).then(function() {
// 微任务 待主线程中任务执行完成之后再执行微任务队列中的所有任务
console.log('promise then')
})
2. async/await
async function async1(){
// 同步执行
console.log('async1 start')
await async2()
// 微任务
console.log('async1 end')
}
async function async2(){
// 同步执行
console.log('async2')
}
async1()
// 示例2打印顺序:async1 start async2 async1 end
事件循环
-
先执行主线程中的同步任务
-
遇到宏任务、微任务,先将宏任务放入macro queue中,再将微任务放入micro queue中
-
待主线程中的同步任务执行完毕后,取出第一轮微任务队列中的所有任务放入主线程中,依次执行;然后再从宏任务队列中取出一个宏任务到主线程中执行
-
循环1、2、3步骤。
例子:
setTimeout(function(){
console.log('setTimeout');
},0)
console.log('script start');
async function async1() {
console.log('async1 start');
await async2()
console.log('async1 end');
}
async function async2() {
console.log('async2 end');
}
new Promise(function(resolve) {
console.log('promise');
for(var i=0; i < 10000; i++) {
if (i === 10) {
console.log('3');
}
i == 9999 && resolve('4')
}
resolve()
}).then(function(val){
console.log(val);
console.log('promise1');
}) .then(function(res){
console.log(res);
console.log('promise2');
})
async1()
console.log('script end');
// 执行顺序
// script start
// promise
// 3
// async1 start
// async2 end
// script end
// 4
// promise1
// async1 end
// undefined
// promise2
// setTimeout