概念
首先,JavaScript是一门单线程的语言,意味着同一时间内只能做一件事,但是这并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环。
在JavaScript中,所有的任务都可以分为
- 同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行
- 异步任务:异步执行的任务,比如
ajax网络请求,setTimeout定时函数等
任务开始时,同步任务进入主线程,异步任务进入任务队列,主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行。上述过程的不断重复就事件循环
-
微任务:
- Promise.then
-
宏任务
- setTimeout/setInterval
- 执行一个宏任务,如果遇到微任务就将它放到微任务的事件队列中
- 当前宏任务执行完成后,会查看微任务的事件队列,然后将里面的所有微任务依次执行完。
总结:
任务没有优先级,但是消息队列有优先级。
JS是一门单线程语言,所以同一时间只能做一件事,所以如果碰到网络请求等就会卡住。但是JS把所有的任务分成同步任务、微任务(promise.then)宏任务(setTimeout setInterval)。任务开始时,JS按照上下文循序执行,碰到同步任务则立马执行,微任务或者宏任务则放到微队列和宏队列后续执行。当执行完所有的同步任务之后,再去执行微任务,然后时宏任务,但是有可能在执行宏任务的时候碰到微任务,则暂停宏任务执行去执行微任务…..依次直到所有任务执行完,这就是事件循环机制,某种意义上实现了单线程永不阻塞。
async与await
async 是异步的意思,await则可以理解为 async wait。所以可以理解async就是用来声明一个异步方法,而 await是用来等待异步方法执行
async : 异步
function f() {
return Promise.resolve('TEST');
}
// asyncF is equivalent to f!
async function asyncF() {
return 'TEST';
}
await:不管await后面跟着的是什么,await都会阻塞后面的代码
async function f(){
// 等同于
// return 123
return await 123
}
f().then(v => console.log(v)) // 123
题目训练
- 题目一
console.log("start");
setTimeout(() => {
console.log("children2")
Promise.resolve().then(() =>{
console.log("children3")
})
}, 0)
new Promise(function(resolve, reject){
console.log("children4")
setTimeout(function(){
console.log("children5")
resolve("children6")
}, 0)
}).then(res =>{// flag
console.log("children7")
setTimeout(() =>{
console.log(res)
}, 0)
})
-
输出结果:
startchildren4children2children3children5children7children6
- 题目二
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2')
}
console.log('script start')
setTimeout(function () {
console.log('settimeout')
})
async1()
new Promise(function (resolve) {
console.log('promise1')
resolve()
}).then(function () {
console.log('promise2')
})
console.log('script end')
-
输出结果:
script startasync1 startasync2promise1script endasyn1 endpromise2settimeout