事件循环,面试看这个就够了。

138 阅读2分钟

概念

首先,JavaScript是一门单线程的语言,意味着同一时间内只能做一件事,但是这并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环。

JavaScript中,所有的任务都可以分为

  • 同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行
  • 异步任务:异步执行的任务,比如ajax网络请求,setTimeout定时函数等

任务开始时,同步任务进入主线程,异步任务进入任务队列,主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行。上述过程的不断重复就事件循环

  1. 微任务:

    • Promise.then
  2. 宏任务

    • 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

题目训练

  1. 题目一
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)
})
  • 输出结果:

    1. start
    2. children4
    3. children2
    4. children3
    5. children5
    6. children7
    7. children6
  1. 题目二
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')
  • 输出结果:

    1. script start
    2. async1 start
    3. async2
    4. promise1
    5. script end
    6. asyn1 end
    7. promise2
    8. settimeout