前置知识点:

事件循环机制

相信读者读完以上推荐的文章后,已经知道事件循环机制是怎么一回事了吧,也能从容应对面试。接下来我要谈谈自己的理解:

为什么会有事件循环机制

  • js设计之初就是单线程模式,代码也都是顺序执行,当遇到因为大量计算、http请求等需要额外的等待时间时,浏览器用户就会体验到卡顿了,所以所有的设计和改进初衷只有一个就是要快

事件循环机制的产生

  • 浏览器说我的内核是多线程,可以辅助JS引擎线程啊,Web Worker线程提供大量计算辅助(不能操作DOM),事件触发线程定时触发器线程异步http请求线程


  • 执行栈(先进后出),由JS引擎线程控制,引用下面这个例子谈谈自己的理解:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    console.log('script start');
    
    setTimeout(function() {
    console.log('setTimeout');
    }, 0); Promise.resolve().then(function() {
    console.log('promise1');
    }).then(function() {
    console.log('promise2');
    });
    console.log('script end'); // "script end"
    // "promise1"
    // "promise2"
    // "setTimeout"
  • ES5还没有Promise时代,异步回调很常见,上面例子中,通过解读Promise源码(前端面试必考题Promise的源码解析),我们可以把Promise转换成如下图式回调(个人理解,文章中的Promise源码也只是模拟,大部分浏览器已经原生支持)。

    1. 打印完script start, script end主执行栈出栈,如果Promise.resolve().then换成new Promise(executor),脑补Promise换成回调函数,那么这个函数一执行,executor函数也就执行了,然后遇到异步回调,回调函数被其它对应的线程接手,启动观察者模式,完成后回调函数被推入事件任务队列,等待执行栈空了进入主线程执行

    2. 以上这种在异步函数中放同步函数的例子,为了合理解释输出顺序而推出了microtasks微任务的概念,请看下面的例子,脑补Promise换成回调函数,Promise.prototype.then内部执行了return new Promise(),js引擎在捕捉到Promise时,放到了由js引擎自身控制的微任务队列等待执行,也就造成promise1、2、3、4错开打印

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      console.log('script start');
      
      new Promise(function(resolve, reject) {
      console.log('promise1');
      resolve();
      }).then(function() {
      console.log('promise2');
      }); new Promise(function(resolve, reject) {
      console.log('promise3');
      resolve();
      }).then(function() {
      console.log('promise4');
      }); console.log('script end'); // "promise1"
      // "promise3"
      // "script end"
      // "promise2"
      // "promise4"
    3. micro 大专栏  对javascript EventLoop事件循环机制不一样的理解tasks微任务的概念完全为了解释异步函数中放同步函数的场景,而且各类文章和面试都是这种题目和例子,在实际开发过程中,你会在Promise中这么写么?,在我看来这种比较打印顺序太过于理论,而且可能会混乱你的思绪。就像下面的例子,Promiseresolve决定了Promise状态,就像在回调函数中满足了条件才会继续执行,例子中只是用setTimeout模拟异步请求,用之前的理论你可能觉得setTimeout被放入了事件任务队列,那没有resolvePromise怎么解释呢?(放到微任务里一直阻碍第一个setTimeout宏任务执行吗?显然是不可能的,这不是跟设计事件循环机制初衷冲突了么

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      setTimeout(function() {
      console.log('setTimeout');
      }, 0); new Promise(function(resolve, reject) {
      setTimeout(function() { // 模拟异步请求
      console.log('promise1');
      resolve();
      }, 0);
      }).then(function() {
      console.log('promise2');
      }); new Promise(function(resolve, reject) {
      // resolve(); 注释掉resolve,使Promise一直处于‘pending’状态
      }).then(function() {
      console.log('promise2');
      }); // "setTimeout"
      // "promise1"
      // "promise2"
    4. 个人认为把Promiseasync/await脑补成原始的回调函数(模拟源码中模拟异步是用的setTimeout函数),而js引擎捕捉到setTimeout, setInterval就转给定时触发器线程处理,捕捉到XMLHttpReuqest, fetch就转给异步http请求线程,跟事件触发线程一起管理着事件任务队列,微任务的概念可以看作是当事件触发线程遇到几乎同时需要把回调函数放到事件任务队列时,Promise内部的异步标识函数优先级高于setTimeout函数吧,以上例子中没有执行resolvePromise状态一直处于’pending’,事件触发线程压根没有放入到事件任务队列,总之浏览器会安排的妥妥的,不要打架,虽然js引擎线程只有一个(听我指挥排好队,咱们这都是同步代码执行ms级别,我开了很多其它线程处理需要等待的代码了)。以下例子模拟所谓的几乎同时把回调函数放到事件任务队列,记得把Promise脑补成原始的回调函数。仿佛回到了没有微任务的时代。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      setTimeout(function() {
      console.log('setTimeout');
      }, 0); new Promise(function(resolve, reject) {
      setTimeout(function() { // 模拟异步请求
      console.log('promise1');
      resolve();
      }, 2000);
      }).then(function() {
      console.log('promise2');
      }); new Promise(function(resolve, reject) {
      setTimeout(function() { // 模拟异步请求
      console.log('promise3');
      resolve();
      }, 2000);
      }).then(function() {
      console.log('promise4');
      }); // "setTimeout"
      // "promise1"
      // "promise2"
      // "promise3"
      // "promise4"

以上内容纯属未深入了解js情况下的个人理解,感觉是在努力摒弃微任务的概念,回归ES5回调函数时代,便于自身理解事件循环机制而做出的遐想。

多环境下的事件循环机制

在node环境、浏览器环境以及各个不同版本下js引擎处理的方式还不太一样。node比浏览器还复杂些

对javascript EventLoop事件循环机制不一样的理解的更多相关文章

  1. JavaScript的事件循环机制浅析

    前言 JavaScript是一门单线程的弱类型语言,但是我们在开发中,经常会遇到一些需要异步或者等待的处理操作. 类似ajax,亦或者ES6中新增的promise操作用于处理一些回调函数等. 概念 在 ...

  2. 【运行机制】 JavaScript的事件循环机制总结 eventLoop

    0.从个例子开始 //code-01 console.log(1) setTimeout(() => { console.log(2); }); console.log(3); 稍微有点前端经验 ...

  3. javascript的事件循环机制

    JavaScript是一门编程语言,既然是编程语言那么就会有执行时的逻辑先后顺序,那么对于JavaScript来说这额顺序是怎样的呢? 首先我们我们需要明确一点,JavaScript是单线程语言.所谓 ...

  4. JavaScript 运行机制:Event事件循环机制

    JavaScript Event事件循环机制 JS是单线程的,浏览器只分配一个主线程给JS.一次只能执行一个任务,当前任务执行完后在可以执行下一个任务.任务多时,就会形成任务队列排队等待执行.但是非常 ...

  5. 深入理解JavaScript事件循环机制

    前言 众所周知,JavaScript 是一门单线程语言,虽然在 html5 中提出了 Web-Worker ,但这并未改变 JavaScript 是单线程这一核心.可看HTML规范中的这段话: To ...

  6. javascript事件循环机制 浅尝手记

    引入 众所周知Javascript是一个单线程的机制,虽然可以依托多线程的浏览器实现页面如何实现页面复杂的渲染.事件响应,但仍不会改变其单线程的本质:所以对于js的事件循环机制的了解是一个前端人员的必 ...

  7. selector.select(500); EventLoop及事件循环机制 netty 在半透明做代理网关下 对请求的批处理

    Netty框架学习之路(五)—— EventLoop及事件循环机制 - 懋懋之为 - CSDN博客 https://blog.csdn.net/tjreal/article/details/79751 ...

  8. 深入浅出Javascript事件循环机制

    一.JS单线程.异步.同步概念 众所周知,JS是单线程(如果一个线程删DOM,一个线程增DOM,浏览器傻逼了-所以只能单着了),虽然有webworker酱紫的多线程出现,但也是在主线程的控制下.web ...

  9. 浏览器中的JavaScript事件循环机制

    浏览器的事件循环机制是HTML中定义的规范. JavaScript有一个主线程和调用栈,所有的任务都会被放到调用栈等待主线程执行. JS调用栈 是一种先进后出的数据结构.当函数被调用时,会被添加到栈中 ...

随机推荐

  1. 微信H5支付demo

    首先我们必须得在微信公众平台和微信商业平台那边配置好相关配置 1.注册微信服务号,开通微信支付权限绑定微信商业平台(这个具体怎么操作我就不说了) 2.获取应用(公众号)appid.应用(公众号)秘钥. ...

  2. 题解-------CF1304E 1-Trees and Queries

    传送门 题目大意 给你一棵无根树,然后询问Q次,每次把点$x$和点$y$连接,问你从点$a$到点$b$是否有一条长度为$k$的简单路径,每次询问完后会把新添加的边删除. 思路:树上LCA 题目跟201 ...

  3. Uncaught (in promise) NavigationDuplicated {_name: "NavigationDuplicated"}的解决方法

    左侧菜单栏时,发现点击路由跳转相同地址 会有这个报错 Uncaught (in promise) NavigationDuplicated {_name: "NavigationDuplic ...

  4. centos7 国内镜像yum安装mysql5.7

    我这里是采用纯净的系统,刚装的centos7,而且选择的最小安装所以基本上是什么环境都没有的,然后这篇文章主要针对于小白 检查mysql环境是否已存在 虽然我的是纯净系统,但别人的不能保证,为了避免发 ...

  5. django框架进阶-解决跨域问题

    ####################################### """ 一.为什么会有跨域问题? 是因为浏览器的同源策略是对ajax请求进行阻拦了,但是不 ...

  6. UFT场景恢复

    场景恢复: 在脚本运行中可能会出现一些非预期事件.错误.程序崩溃等情况,阻止脚本继续执行下去,在此情况下脚本可能暂停执行, 直到某些界面被操作之后才会继续执行下去,为了处理这一类事件因此存在场景恢复. ...

  7. Java生成随机图片验证码

    前台html代码 [Java] 纯文本查看 复制代码 ? 01 02 03 04 05 06 07 08 09 10 <div style="margin-top: 50px;&quo ...

  8. OpenCV 特征描述

    #include <stdio.h> #include <iostream> #include "opencv2/core/core.hpp" #inclu ...

  9. django框架基础-ORM基础-长期维护

    ###############    ORM介绍  ################ """ ORM简介: ORM 全拼Object-Relation Mapping. ...

  10. git 忽略规则

    # 以'#'开始的行,被视为注释. # 忽略掉所有文件名是 foo.txt的文件. foo.txt # 忽略所有生成的 html文件, *.html # foo.html是手工维护的,所以例外. !f ...