JS事件循环机制-eventLoop
JS事件循环机制
进程和线程
浏览器打开一个页面就相当于开一个进程,在进程中,我们会同时做很多事情,每一个事情都有一个“线程”去处理,所以一个进程中可能会包含多个线程!!
浏览器是多线程的: GUI渲染线程:渲染页面 & 绘制图形 JS引擎线程:渲染和解析JS代码 事件触发线程:监听事件触发 定时触发器线程:给定时器计时的 异步HTTP请求线程:基于HTTP网络从服务器端获取资源和信息 WebWorker ...
同时做多件事情是“异步编程”; 一次只能处理一件事情,上一件事情处理完,下一件才能开始处理,这种操作是“同步编程” 异步编程实现的机制
多线程机制
EventLoop事件循环机制
...
JS是单线程的(浏览器只分配一个线程“JS引擎线程”用来渲染和解析JS代码)
定时器:setTimeout/setInterval
事件绑定/队列
数据请求:Ajax/Fetch
MessageChannel
setImmediate[NODE]
...
Promise.then/catch/finally
async/await
queueMicrotask
MutationObserver
IntersectionObserver
requestAnimationFrame
process.nextTick[NODE]
...
JS中的大部分代码操作都是“同步”
有少部分操作,结合Eventloop机制,实现了“异步”处理
[异步宏任务:macrotask]
[异步微任务:microtask]
JS事件循环解析
console.log(1); setTimeout(() => { console.log(2); }, 0); console.log(3); for (let i = 0; i < 99999999; i++) {} //100MS左右 console.log(4); 复制代码
setTimeout(() => { console.log(1); }, 20); console.log(2); setTimeout(() => { console.log(3); }, 10); console.log(4); for (let i = 0; i < 90000000; i++) {} console.log(5); setTimeout(() => { console.log(6); }, 8); console.log(7); setTimeout(() => { console.log(8); }, 15); console.log(9); 复制代码
promise的使用总结
let p1 = new Promise((resolve, reject) => { console.log(1) resolve(100) console.log(2) }) console.log(p1) //fulfilled 100 //p1.then 如果已知promise实例的状态,我们就把执行的方法onfulfilled或者onrejected放在EventQueue的异步微任务队列中等待执行[并不会立即执行方法,也即是then其实是异步的任务] let p2 = new Promise((resolve, reject) => { setTimeout(() => { resolve(100) //立即更新实例的状态和 值,但是通知之前存储的方法执行这个操作是“异步”的 console.log(2) },1000) }) console.log(p1) //pending //如果此时还不知道p1实例的状态,则我们会把onfulfilled/onrejected存储在一个容器中,等到后期我们基于resolve/reject把实例状态修改后,则在通知之前存放的方法执行【但是也不是立即执行,而是放在异步的微任务等待队列中】 p1.then(result => { console.log(`成功:${result}`); }, reason => { console.log(`失败:${reason}`); }); console.log(3); // 3 2 成功:100 // 基于then返回的promise实例,它的状态和值,主要看onfulfilled/onrejected执行 // - 函数返回的不是promise实例:方法执行不报错,p2状态是成功,值是返回值;方法执行报错,则p2是失败的,值是报错原因 // - 函数返回的是个promise实例:则这个实例的状态和值决定了p2的状态和值 let p1 = Promise.resolve(100); console.log(p1); //fulfilled let p2 = p1.then(result => { //p1.then的时候,此处的onfulfilled方法放在EventQueue中等待执行(@A) console.log(`成功:${result}`); return 1000; }); console.log(p2); //pending p2.then(result => { //此时还不知道p2的状态,所以先把onfulfilled存储起来(@B) console.log(`成功:${result}`); }); console.log('SYNC END'); //同步结束后开始执行@A -> 成功:100并且修改p2的状态是成功,值是1000; //此时才知道@B可以执行了,把其也放在等待的异步微任务队列中 -> 如果没有其他的异步任务执行,这把@B也拿出来执行 -> 成功:1000 复制代码
async/await使用总结
const query = () => { return new Promise(resolve => { setTimeout(() => resolve(300),1000) }) } (async () => { //如果await后面放置的不是一个Promise实例,则浏览器默认会把其转换为一个“状态为成功,值就是await后的值”的promise实例 // - await需要等待后面的promise实例是状态为成功的,才会执行下面的代码 // - 首先当前上下文中,await下面的代码都是异步的微任务 @aw // - 如果已经知道await后面的实例状态是成功的,则 @aw 直接放在EventQueue中,等待执行即可 // - 如果后面实例状态是失败的,则 @aw 在webapi中永远不会进入到EventQueue中,因为永远不会执行 // - 如果暂时还不知道是成功还是失败,则@aw 先放置在webapi中,等到知道实例状态是成功后,在挪至到EventQueue中等待执行 let result = await 1 //await Promise.resolve(1) console.log(result); result = await Promise.resolve(2) console.log(result) result = await querey(); // 先把query执行,把返回的promise实例放在await后面等着,当前案例只有1000ms后,才能知道实例状态 })()
作者:前端肉包子
链接:https://juejin.cn/post/7034785804337545252