EventLoop事件循环(javaScript)

文章详细阐述了JavaScript中的EventLoop概念,包括同步任务、异步任务的区分,以及宏任务和微任务的定义。它解释了EventLoop的执行机制,即同步任务在主线程执行,异步任务在任务队列等待,微任务在宏任务之前执行。并通过三个案例分析了具体执行顺序。
摘要由CSDN通过智能技术生成

一、概念

1. EventLoop 概念

           Event Loop即事件循环,是指浏览器或Node的一种解决javaScript单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。

           因为JavaScript就是单线程,也就是说,同一个时间只能做一件事。单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。

        所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。

2.同步任务和异步任务

   同步任务:会立即执行的任务
   异步任务:不会立即执行的任务(异步任务又分为宏任务与微任务)

在异步任务中,任务被分为两种,一种宏任务(MacroTask)也叫Task,一种叫微任务(MicroTask)。

3. 宏任务和微任务

    宏任务:由宿主对象发起的任务(setTimeout)

宏任务包括 script, setTimeout,setInterval,setImmediate(Node.js),I/O,postMessage, MessageChannel,UI rendering

    微任务:由js引擎发起的任务(promise)

微任务包括 process.nextTick(Node.js),promise.then(),promise.catch(),MutationObserver。

二、EventLoop 执行机制

             由上述可知,在代码执行的过程中,同步任务会立即执行,异步任务会通过一些手段和过程才会拿到结果。所以在异步任务等待结果的同时,可先执行其后的同步任务。当异步任务有结果的时候,在回过头来执行异步任务。

 EventLoop 的执行机制如下:

(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。

(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。

(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。

(4)主线程不断重复上面的第三步。

三、案例解析

1. 例题1

setTimeout(() => {
  console.log('A');
}, 0);
var obj = {
  func: function() {
    setTimeout(function() {
      console.log('B');
    }, 0);
    return new Promise(function(resolve) {
      console.log('C');
      resolve();
    });
  },
};
obj.func().then(function() {
  console.log('D');
});
console.log('E');
根据事件循环机制的执行顺序,上述代码执行步骤如下:

(1)执行 setTimeout ,由于是宏任务,将其放置进宏任务队列,此时宏任务队列为 [ 'A ’ ]

(2)执行 obj.func() , 先执行 setTimeout,由于是宏任务,将其放置进宏任务队列,此时宏任务队列为
 [ 'A ','B ’ ]

(3)函数返回值是一个 Promise,因为这是一个同步操作,所以先打印出 'C ’

(4) promise.then() , 由于是一个微任务,将其放置进微任务队列,此时微任务队列为 [ 'D ’ ]

(5)执行同步任务,打印出 'E ’

(6)微任务队列与宏任务队列均存在数据,但是微任务永远比宏任务先执行(换句话说 先清掉现存的微任务之后,才会执行宏任务队列),所以先打印 'D ’

(7)执行宏任务,依次打印出来 'A ’ 和 'B ’


答案:C -> E -> D -> A -> B

2. 例题2

function go() {
  console.log(5)
}
let p = new Promise(resolve => {
  resolve(1);
  Promise.resolve(go()).then(() => console.log(2));
  console.log(4);
}).then(t => console.log(t));
console.log(3);
上述代码执行步骤如下:

(1)在 new Promise的时候,就会执行内部的方法。首先就是执行 resolve(1) ,将 1 返回到 then 里
(2)执行内部的 Promise.resolve( go() ) ,因为这是一个普通函数,是一个同步执行的代码,所以会打印出 5
(3)promise.then()是一个微任务,会将 console.log(2) 放置到微任务队列,此时微任务队列为 [ 2 ]
(4)顺序执行同步任务 console.log(4),将 4打印出来
(5)执行 new Promise 的 then() 方法,由于这也是一个微任务,所以会放置到微任务列表,此时微任务队列为 [ 2 ,1 ]
(6)顺序执行同步任务 console.log(3),将 3打印出来
(7)依次打印出微任务队列的 2 和 1

答案: 5 -> 4 -> 3 -> 2 -> 1

3. 例题3   async/await

async/await 是生成器的语法糖,把它转换成 Promise 的形式

async function foo() {
  console.log(1)
  await bar();
  console.log(2)
}
async function bar() {
   console.log(3)
}
foo();

转换成 Promise的形式:

 function foo(){
	 console.log(1)
	 Promise.resolve(bar()).then(()=>{
		 console.log(2)
	})
}
function bar(){
	 console.log(3)
}
foo()

执行步骤如下:

(1)执行 foo() ,打印同步代码 内容 1
(2)顺序执行 Promise.resolve() ,同步执行 bar() 方法,打印 3
(3)Promise.thenr() 是一个微任务,将其放置到 微任务队列,此时微任务队列为[ 2 ]
(4)执行微任务队列,打印队列内容 2


答案:  1 -> 3 -> 2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值