Event Loop事件循环

293 阅读3分钟

这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战

首先需要明白什么是Event Loop?Event Loop就是计算机系统的一种运行机制。JavaScript就是采用的这种机制 ,来解决单线程运行带来的一些问题。

1. JavaScript为什么是单线程的?

JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。举个例子:假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这样就会出现一些问题。

2. 任务队列

单线程就意味着所有的任务都需要排队执行,只有上一个任务执行完才会执行下一个任务。如果上一个任务执行耗时很长,那下一个任务就得一直等着。如果是因为任务工作量比较大导致CPU忙不过来了,那等着就等着吧,但是很多时候CPU也是空闲的,这样就会有点不太妥。所有任务分为了两种:同步任务和异步任务。

同步任务就是在主线程上执行,形成一个执行栈,只有上一个任务执行完下一个任务才会开始。

异步任务就是不进入主线程而进入子线程,它不会影响主线程的工作,主线程会照常执行。而当异步任务有的结果后,比如AJAX获取到数据了,那么回调函数就会被放到 任务队列(task queue) 中。

当主线程的 执行栈 所有的同步任务执行完毕后,那么系统就会读取 任务队列,任务队列是一个先进先出的队列,就会将任务队列中的回调函数拿到主线程去执行。

3. 宏任务和微任务

对于异步任务又分为宏任务和微任务

宏任务

宏任务包含:script标签中整体的代码块,setTimeout、setInterval等...

微任务

微任务包含:Promise.then()、$vue.nextTick等...

async await

async await是ES7的语法,async要写在一个函数声明的前面,表明这个函数是一个异步函数;await要搭配async组合使用,写在async函数内部,相当于是将await后面紧跟的异步函数变成的了同步的。

  • 对于await,await执行完后面的函数之后,下面的同步逻辑会被 放到该轮微任务执行栈的最后。

理解

对于我自己的理解,当JavaScript在执行时,相当于是有三个执行栈,一个是同步执行栈:所有代码从上到下依次执行,上一步会阻塞下一步的运行。二是微任务执行栈:JavaScript由上到下依次执行,当碰到微任务时会将这个回调函数放到微任务执行栈中。三是宏任务执行栈JavaScript由上到下依次执行,当碰到宏任务时会将这个回调函数放到宏任务执行栈中。当同步执行栈代码执行完毕时,系统会到微任务执行栈中找,当微任务执行栈的任务执行完毕后再执行宏任务执行栈中。

例子

  • 例子1
console.log('1')

setTimeout(function () {

  console.log('2')

});

new Promise(function (resolve) {

  console.log('3');

  resolve();

}).then(function () {

  console.log('4')

  setTimeout(function () {

    console.log('5')

  });

});

new Promise(function (resolve) {

  console.log('6');

  resolve();

  }).then(function () {

    console.log('7')

  setTimeout(function () {

    console.log('8')

  });

});

  • 例子2
async function aaa() {

  function fun1 (num) {

    console.log(num)

  }

  new Promise((res) => {

    fun1(3);

    res(4)

  }).then((res) => {

    fun1(res);

  })

  await fun1(1);

  fun1(2)

  }

  aaa();

  async function aaa() {

    function fun (num) {

      console.log(num)

    }

    new Promise((res) => {

      fun(3);

      res(4)

    }).then((res) => {

      fun(res);

    })

    setTimeout(() => {

      fun(5);

    },0)

    await fun(1);

    fun(2)

    }

    aaa();
  • 例子3
async function async1() {

  console.log(1)

  await async2()

  console.log(2)

}

async function async2() {

  console.log(3)

}

console.log(4)

setTimeout( e =>{

  console.log(5)

},0)

async1()

new Promise( res =>{

  console.log(6)

  res()

}).then( e => {

console.log(7)

})

console.log(8)