重温V8引擎事件循环,反思异步带来的现代化开发壁障

重温V8引擎事件循环,反思异步带来的现代化开发壁障

四月 12, 2021 本文共计: 1k 字 预计阅读时长: 4分钟

孔夫子有云:温故而知新。

不断的回味以前对于知识的理解,不断的实践,不断的推翻,逆向思考,新的知识就会慢慢浮现。

一分钟理解微任务、宏任务

宏任务:

  • DOM事件
  • setTimeout
  • setInterval
  • 脚本
  • I/O

微任务

  • promise
  • GC
  • 等等

当然,requestIdleCallbackrequestAnimationFrame不属于task,它们是浏览器渲染过程的一步,和taskmicrotask的执行是分离的。

小二,先上一道烂大街的面试题!

讲述下事件循环:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
console.log('同步代码开始')

async function asycn1() {
console.log('2')
}

async function async2() {
console.log('3')
await async1()
console.log(4)
}

console.log('同步代码结束')

答案公布:

同步代码开始

3

2

同步代码结束

4

第一步:整个代码块被扔进了宏任务中;

第二步:console同步代码被放入执行栈中开始执行,打印 同步代码开始

第三步:Promise构造函数是同步代码,压栈执行,打印32

第四步:console同步代码被放入执行栈中开始执行,打印 同步代码结束

第五步:宏任务代码执行完毕,检查是否有微任务代码可以执行。

第六步:async函数中的出现 await 后,之后的代码被放入Promise.then中,微任务队列开始执行。

参考链接

【1】从一道题浅说js事件循环(https://github.com/dwqs/blog/issues/61

【2】requestIdleCallback和requestAnimationFrame详解(https://www.cnblogs.com/cangqinglang/p/13877078.html

反思壁障

alt

由快慢async发出的思考

【1】slow-async-await(https://mdn.github.io/learning-area/javascript/asynchronous/async-await/slow-async-await.html)

【2】fast-async-await(https://mdn.github.io/learning-area/javascript/asynchronous/async-await/fast-async-await.html)

接下来,我们慢慢食用代码:

timeoutPromise

1
2
3
4
5
6
7
8
function timeoutPromise(interval) {
return new Promise((resolve, reject) => {
setTimeout(function(){
resolve("done");
}, interval);
});
};

计时程序

1
2
3
4
5
6
7
let startTime = Date.now();
timeTest().then(() => {
let finishTime = Date.now();
let timeTaken = finishTime - startTime;
alert("Time taken in milliseconds: " + timeTaken);
})

slow-async-await

1
2
3
4
5
6
async function timeTest() {
await timeoutPromise(3000);
await timeoutPromise(3000);
await timeoutPromise(3000);
}

fast-async-await

1
2
3
4
5
6
7
8
9
10
async function timeTest() {
const timeoutPromise1 = timeoutPromise(3000);
const timeoutPromise2 = timeoutPromise(3000);
const timeoutPromise3 = timeoutPromise(3000);

await timeoutPromise1;
await timeoutPromise2;
await timeoutPromise3;
}

看下MDN的解释:

这句同时启动它们的关联进程可能很难理解,其实不难,理解了async await—> promise后,原理一目了然:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 转换前

async function async1() {
console.log(1)
}

// 转换后

function async1() {
return new Promise((res) => {
console.log(1);
res();
})
}

起因就是因为async将异步代码真的同步化了,导致同步代码也进入了异步等待中,所以使用变量保存Promise的执行状态,实际上可以理解为并行执行了异步的构造任务

参考链接

【1】MDN(https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Asynchronous/Async_await

【2】js异步梳理:1.从浏览器的多进程到JS的单线程,理解JS运行机制(https://www.cnblogs.com/hezhi/p/10484884.html

【3】为什么要在变量中存储Promise对象?(https://www.debugcn.com/article/53568001.html

useState闭包引发的思考与如何跳出闭包壁障

国际惯例,先扔一道烂大街的面试题:

React 闭包陷阱如何用 useReducer 解决?

              ---- 阿里云前端面试

直接上代码地址:https://imweb.io/topic/5cd845cadcd62f86299fcd76

问题原因请慢慢食用,解决方案如下:

  • useState 的实现原理就是利用了闭包。

官方原话是:useEffect、useMemo、useCallback都是自带闭包的。每一次组件的渲染,它们都会捕获当前组件函数上下文中的状态(state, props),所以每一次这三种hooks的执行,反映的也都是当前的状态,你无法使用它们来捕获上一次的状态。

  • 怎么解决呢?

useReducer 的 dispatch 可以在全局中保持唯一不变的引用,所以用它更新一定能操作最新的值,其次是借助 setState 使用函数更新,更新当前闭包 作用域的旧值,还可以借助 useRef 在外围拿到最新值,因为对象引用不变,所以也能拿到最新值,其次是添加依赖项。

End

以上就是今日份的知识总结,请君慢用~~~