前端-事件循环

49 阅读2分钟

事件循环(消息队列)

为啥要用事件循环?防止主线程阻塞 js是单线程的脚本语言,在同一时间,只能做同一件事。

一个渲染任务过来了。 同步任务:立刻能处理的任务。 js运行时 会立刻放进 执行栈 中 异步任务:无法立即处理的任务。任务的回调会被放进 消息队列

如何处理渲染任务? 主线程循环:主线程不断循环,执行 执行栈中的代码。 执行完毕,才检查消息队列中是否有任务;有就放进去执行,没有就休息。

消息队列

  1. 微队列:  
    • async await
    • Promise.then()Promise.catch()Promise.finally()
    • new Promise(resolve, reject){ } 的 resolve 或 reject 的处理函数
    • MutaionObserver( ) 监视DOM变化
  2. 交互队列(宏任务-高优先级):
    • UI 渲染
    • requestAnimationFrame 在渲染前执行,属于宏任务但优先级高于普通任务
    • 用户事件:addEventListener(‘‘onclick’’, handleClick() )
    • 网络请求:fetch( ) 、 axois()
    • 跨文档通信: window.postMessage( )
    • 文件读写:fs.readFile(Node.js)
  3. 延迟队列(宏任务-低优先级):setTimeout( ) 与 setInteval( )

避坑指南

  1. 牢记微任务优先:任何 Promise 的 .then() 回调都会在当前同步代码执行完毕后立即执行。
  2. 宏任务必须等待setTimeoutsetInterval 等回调属于宏任务,必须等到所有微任务执行完毕后才会执行。
  3. 嵌套的微任务按顺序执行:即使微任务嵌套在另一个微任务中,它们仍会按添加顺序依次执行。
  4. 链式调用中的返回值:返回 Promise 会影响后续 .then() 的执行时机。 .then()要等到前面执行完才放入微任务

题一

console.log('start');

setTimeout(() => console.log('timeout1'), 0);

Promise.resolve()
  .then(() => {
    console.log('promise1');
    setTimeout(() => console.log('timeout2'), 0);
    return Promise.resolve().then(() => console.log('promise2'));
  })
  .then(() => console.log('promise3')); `.then要等到前面执行完才执行`

console.log('end');
--------------------------

执行栈 
console.log('start')
console.log('end')
console.log('promise1')
console.log('promise2')
console.log('promise3')
console.log('timeout1')
console.log('timeout2')

微
() => {
    console.log('promise1');
    setTimeout(() => console.log('timeout2'), 0);
    return Promise.resolve().then(() => console.log('promise2'));
})
.then(() => console.log('promise3'));
-------------------------------
() => console.log('promise2')
() => console.log('promise3')

宏 
() => console.log('timeout1')
() => console.log('timeout2')


题二

await后面 相当于 Promise.resolve().then() 要放入微任务

async function async1() {
  console.log('async1 start');
  await async2();
  console.log('async1 end');   `await后面 相当于 promise.then()`
}

async function async2() {
  console.log('async2');
}

console.log('script start');

setTimeout(() => console.log('setTimeout'), 0);

async1();

new Promise(resolve => {
  console.log('promise1');
  resolve();
  console.log('after promise1');
}).then(() => console.log('promise2'));

console.log('script end');
--------------------------------
// 执行栈
console.log('script start')
console.log('async1 start')
console.log('async2')
console.log('promise1');
console.log('script end')
console.log('async1 end')
console.log('promise2')
console.log('setTimeout')

// 微任务
()=> console.log('async1 end')
() => console.log('promise2')

// 宏任务
() => console.log('setTimeout')

题三

宏任务中有微任务,立刻执行微任务

await后面的代码,一定要跟在后面写 ).then(()=>{ xxx })

async function async1() {
  console.log(1);
  await async2(); `await后面的代码,一定要跟在后面写 ).then(()=>{ xxx })`
  console.log(2);  
  setTimeout(() => console.log(3), 0);
}

async function async2() {
  console.log(4);
  await Promise.resolve().then(() => {
    console.log(5);
    setTimeout(() => console.log(6), 0);
  });
}

console.log(7);

setTimeout(() => {
  console.log(8);
  Promise.resolve().then(() => console.log(9));
}, 0);

async1();

Promise.resolve().then(() => {
  console.log(10);
  setTimeout(() => console.log(11), 0);
});

console.log(12);
-----------------
// 执行栈
console.log(7);
console.log(1);
console.log(4);
console.log(12)
console.log(5)
console.log(10)
console.log(2)
console.log(8)
console.log(9)
console.log(6)
console.log(11)
console.log(3)
// 微
() => {
    console.log(5);
    setTimeout(() => console.log(6), 0);
  }).then(()=>{
    console.log(2);
    setTimeout(() => console.log(3), 0);
  })

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

()=>{
    console.log(2);
    setTimeout(() => console.log(3), 0);
}
//宏
  console.log(8);
  Promise.resolve().then(() => console.log(9)); `宏任务中有微任务,立刻执行微任务`
  () => console.log(6)
  () => console.log(11)
  () => console.log(3)