阅读 311

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); 复制代码

JS事件循环-1.png

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); 复制代码

JS事件循环-2.png

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


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐