EventLoop事件轮询 宏任务和微任务

EventLoop事件轮询 宏任务和微任务

浏览器从服务器获取到代码后,浏览器会开辟一个GUI渲染线程,GUI从上到下开始执行代码。
浏览器是多线程的,包含GUI渲染线程、HTTP网络请求线程(并发数6-7)、事件监听定时器监听。但JS代码的运行是单线程的。

执行过程:执行完宏任务 => 执行微任务 => 页面重新渲染 => 再执行新一轮宏任务

将所有的任务分为2种,一种是同步任务,一种是异步任务。

  • 同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行下一个任务。同步任务是在调用栈call stack中执行。

  • 异步任务: 不进入主线程,进入“任务队列”task queue 的任务,只要异步任务有了运行结果,就会在task queue中放置一个事件。 只有任务队列通知主线程,异步任务可以执行了,该任务才会进入主线程。

  • 任务队列: 是一个事件队列(也可以了解为消息队列)。一旦一个异步任务完成,就在task queue中添加一个事件,表示相关异步任务可以进入“执行栈”了。主线程读取task queue,就是读取里面有哪些事件。

所以同步任务都在主线程上执行,行程一个执行栈。一旦执行栈中所有的同步任务执行完毕,系统就会去读取task queue,看看里面有哪些事件。对应的异步任务,就会结束等待状态,进入执行栈,开始执行。

微任务优先级高于宏任务,先找微任务,微任务只要还有,则继续按微任务,一直到没有微任务,才去执行宏任务。宏任务的优先级是按照谁先到达执行时间。

任务队列 task queue

任务队列分为2中队列

  • macro-task queue: 存放宏任务
    • script
    • setTimeout、setInterval、setImmediate
    • ajax
    • 事件回调
  • micro-task queue:存放微任务
    • Promise.then()、catch()、 finally()、async/await:async函数中的await紧跟函数/语句之后的内容
    • process.nextTick
    • MutaitonObserver:构造器,用来观察node(节点)变化的。

microtask的执行注意点:

  • async函数中:await紧跟函数/语句之后的内容是异步的,会插入到该microtask队列的末尾
  • 对于then的链式调用,只有当前then的上一个then执行完毕之后,当前then才会被加入微任务队列(而不是立即执行,仅仅只是加入队列)
  • 如果在执行 microtask(微任务) 的过程中,又产生了microtask,那么会加入到队列的末尾,也会在这个周期被调用执行。
  • new Promise里面内容直接运行的
  • .then是否执行和promise中是否有返回值相关(resolve或者是return)。
  • .then执行时,会等之前宏任务执行完成后,延迟执行,并且参数和resolve返回的参数相关联 => .then里面的内容是异步的,是微任务,要等同步代码执行完,去microtask queue中依次执行
  • Promise中resolve的结果,一经确认就不再修改。

例子:

new Promise( resolve => {
  console.log(1);
}).then( res => {
  console.log(2);
});
console.log(3);

// 1 3
// 该Promise并没有return或者resolve,那么then里面的代码是不会执行的。

new Promise( resolve => {
  console.log(1);
  resolve()
}).then( res => {
  console.log(2);
});
console.log(3);

// 1 3 2

new Promise( resolve => {
  console.log(1);
  resolve()
}).then( res => {
  console.log(res);
});
console.log(3);

// 1 3 undefined
// then里面的参数跟resolve的参数或者return的值有关
new Promise( (resolve,reject) => {
  console.log(1);
  resolve(2)
  resolve(3)
  reject(4)
}).then( res => {
  console.log(res);
}).catch( res => {
  console.log(res)
}).finally(() => {
  console.log('finally')
});
console.log(3);

// 1 3 2 finally

new Promise( (resolve,reject) => {
  console.log(1);
  resolve()
  resolve(3)
  reject(4)
}).then( res => {
  console.log(res);
}).catch( res => {
  console.log(res)
}).finally(() => {
  console.log('finally')
});
console.log(3);

// 1 3 undefined finally

// Promise中resolve的结果,一经确认就不再修改

Promise和setTimeout结合(微任务、宏任务)

  • 在执行下一个宏任务之前,先清空当前微任务 => 同步任务 --> 微任务 --> 宏任务
console.log('start');
new Promise( (resolve,reject) => {
  console.log('promise');
  resolve('then')
  reject('reject')
  setTimeout( () => {
    console.log('setTimeout')
  },)
}).then( res => {
  console.log(res);
}).catch( res => {
  console.log(res)
});
console.log('end');

// start promise end then setTimeout

// 先执行同步任务: 
// console.log('start'); console.log('promise');(碰到resolve('then'),异步微任务挂起,等该异步微任务有结果后,将该结果消息推入microtask queue中,等待同步执行完再清空microtask queue)(碰到reject,挂起)(碰到setTimeout,宏任务挂起,等该宏任务执行完有结果后,将该任务消息推入 macrotask queue中,等待微任务全部清空后,再进行宏任务进入主线程)console.log('end');
// 同步任务执行完毕,清空mircotask queue
//  console.log('then');
// 清空mircotask queue之后,开启下一个宏任务
//  console.log('setTimeout')


new Promise( (resolve,reject) => {
  setTimeout( () => {
    console.log('setTimeout')
    resolve('then')
  },)
  resolve('then')
}).then( res => {
  console.log(res);
})
// then setTimeout

new Promise( (resolve,reject) => {
  console.log('promise')
  setTimeout( () => {
    console.log('setTimeout')
    resolve('then')
  },)
}).then( res => {
  console.log(res);
})
// promise setTimeout then
var promise1 = ()=>(
  new Promise( (resolve,reject) => {
    console.log('promise1');
    promise2().then( res => {
      console.log(res)
      console.log("promise2-then")
    })
    setTimeout( () => {
      console.log('setTimeout');
      resolve('then1');
    },);
  })
);

var promise2 = () => (
  new Promise( resolve =>{
    console.log('promise2');
    resolve('then2');
  })
);

promise1().then( res => {
  console.log(res);
});
// promise1 promise2 then2 promise2-then setTimeout then1

// 同步任务:=> promise1 promise2
// 1. promise1() => 
// 		1.1 console.log('promise1');
// 		1.2 promise2() => console.log('promise2'); 挂起 微任务 resolve('then2')
// 		1.3. promise2().then( res => {console.log(res)console.log("promise2-then")}) =>  挂起 微任务 promise2().then
// 		1.4. setTimeout => 挂起宏任务setTimeout
// 2. promise1().then( res => { console.log(res); }); => 挂起 微任务 promise1().then
// => promise1 promise2

// 清空微任务 microtask queue  => then2 promise2-then
// 1. 挂起的1.2 跟 1.3 任务执行有结果了: console.log(res) console.log("promise2-then") 这里的res就是1.2传入的'then2'  => console.log('then2') console.log("promise2-then")
// 2. 挂起的2没有结果: console.log(res), 这里的res 没有resolve传入参数,所以这个微任务不能清空
// => then2 promise2-then

// 进行宏任务  => setTimeout
// 1.  setTimeout( () => {console.log('setTimeout');resolve('then1');});
// 同步代码: console.log('setTimeout')
// 挂起微任务resolve('then1');
// => setTimeout

// 清空微任务:=> then1
// resolve('then1') => 上一轮的微任务2【挂起的2没有结果: console.log(res) 】得到了返回结果, console.log('then1')
// => then1


// promise1 promise2 then2 promise2-then setTimeout then1
原文地址:https://www.cnblogs.com/shine-lovely/p/14926096.html