背景

“JavaScript 是单线程、异步、非阻塞、解释型脚本语言”
之前看到这句话会觉得很懵,不太懂是什么意思,抽空复习时候看了一下js的执行机制,这时候对这句话有了一些了解。JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。为了协调事件、用户交互、脚本、UI 渲染和网络处理等行为,防止主线程的不阻塞,Event Loop 的方案应用而生。

js遇到异步是如何执行的

  • 大家都知道js中setTimeout是异步的,看下面代码执行顺序:
    //1
    console.log(1)

    //2
    setTimeout(() => {
        console.log(2)
    }, 1000);
    //3
    console.log(3)

  • 首先js会输出1,然后遇到setTimeout,这时候js不会立即执行,而是发起一个异步,然后接着走到第三步,输出3,这时候执行栈为空,然后会将setTimeout的回调函数压入执行栈进行执行。所以结果为1->3->2

  • 继续看代码:


    console.log(1)

    setTimeout(() => {
        console.log(2)
    }, 0);

    console.log(3)

    setTimeout(() => {
        console.log(4)
    }, 1000);

  • 还是之前的代码,首先肯定会输出1,然后遇到setTimeout,注册函数,接着会输出3,然后又遇到一个setTimeout,注册函数,这时候执行栈已经没有任务,事件触发线程会从消息队列中取出刚才加入队列的函数进行执行,此时会输出2,然后执行栈又为空,这时候事件触发线程又会去消息队列中取出一个函数进行执行,此时会输出4。这就是Event-Loop

微任务

  • 都知道Pormise是微任务,下面就拿Pormise举例子:

    console.log(1)

    setTimeout(() => {
        console.log(2)
    }, 1000);

    let test=new Pormise((resolve)=>{
        console.log(3);
        resolve();
    })
    .then(=>console.log(4))


    console.log(5)

  • 首先会输出1,然后遇到setTimeout,注册任务接着又遇到Pormise,首先先输出3,然后注册任务,接着会输出5,这时候执行栈没有可执行的,然后会从队列中取,这时候会先取出微任务进行执行,进入到then,输出4,这时候执行栈又为空,这时候继续从队列中取出一条任务,这时候会输出2。

练习

  • 检测一下自己到底有木有掌握
    console.log(1)     //同步任务A

    setTimeout(        //同步任务B
    () => { console.log(2) }     //任务B产生的异步宏任务
    , 300)

    new Promise(      //同步任务C
        (resolve) => {  console.log(3);  resolve(4); }
    )
    .then(     //任务C执行过程中resolve(4)语句产生的异步微任务
        (num) => {   console.log(num)   }
    )

    setTimeout(      //同步任务D
    ()=> { console.log(5)  }     //任务D产生的异步宏任务
    , 800)


    //1-3-4-2-5