JS 是单线程的,但是却能执行异步任务,这主要是因为 JS 中存在事件循环(Event Loop)和任务队列(Task Queue)。

事件循环:

JS 会创建一个类似于 while (true) 的循环,每执行一次循环体的过程称之为 Tick。每次 Tick 的过程就是查看是否有待处理事件,如果有则取出相关事件及回调函数放入执行栈中由主线程执行。待处理的事件会存储在一个任务队列中,也就是每次 Tick 会查看任务队列中是否有需要执行的任务。

任务队列:

异步操作会将相关回调添加到任务队列中。而不同的异步操作添加到任务队列的时机也不同,如 onclick, setTimeout, ajax 处理的方式都不同,这些异步操作是由浏览器内核的 webcore 来执行的,webcore 包含上图中的 3 种 webAPI,分别是 DOM Binding、network、timer 模块。

  1. onclick 由浏览器内核的 DOM Binding 模块来处理,当事件触发的时候,回调函数会立即添加到任务队列中。
  2. setTimeout 会由浏览器内核的 timer 模块来进行延时处理,当时间到达的时候,才会将回调函数添加到任务队列中。
  3. ajax 则会由浏览器内核的 network 模块来处理,在网络请求完成返回之后,才将回调添加到任务队列中。

主线程

JS 只有一个线程,称之为主线程。而事件循环是主线程中执行栈里的代码执行完毕之后,才开始执行的。所以,主线程中要执行的代码时间过长,会阻塞事件循环的执行,也就会阻塞异步操作的执行。只有当主线程中执行栈为空的时候(即同步代码执行完后),才会进行事件循环来观察要执行的事件回调,当事件循环检测到任务队列中有事件就取出相关回调放入执行栈中由主线程执行。

  • (所有代码都主线程里跑,主线程没代码了就在任务队列中读回调函数(异步操作)回到主线程里跑)
  1. 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
  2. 主线程之外,还存在一个 "任务队列"(task queue)。只要异步任务有了运行结果,就在 "任务队列" 之中放置一个事件。
  3. 一旦 "执行栈" 中的所有同步任务执行完毕,系统就会读取 "任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
  4. 主线程不断重复上面的第三步。("任务队列" 是一个先进先出的数据结构,排在前面的事件,优先被主线程读取。)

    例1:
    var req = new XMLHttpRequest();
    req.open('GET', url);
    req.onload = function (){}; // 这两个异步方法就会在 ajax 完成后推入任务队列,再由主线程执行
    req.onerror = function (){};
    req.send();

    例2:
    setTimeout(function(){
    // 如果有大量的操作,可能会阻塞 UI 等,则可以使用 setTimeout 让这些操作在主线程把更重要的代码执行完毕之后,再来执行这里的操作。从而提高浏览器的性能。
    },0);// 设置为 0,也会有个最小间隔值,也会在主线程中的代码运行完成后,由事件循环从任务队列将回调添加到执行栈中才执行

    例3:
    // 事件循环测试。执行结果是 2-3-4-1,1在最后输出,说明事件循环是所有同步代码执行完后才开始执行的。

    'use strict';

    setTimeout(function() {
    console.log(1);
    }, 0);

    console.log(2);

    let end = Date.now() + 1000*5;

    while (Date.now() < end) {
    }

    console.log(3);

    end = Date.now() + 1000*5;

    while (Date.now() < end) {
    }

    console.log(4);

JS-线程、事件循环、任务队列的更多相关文章

  1. JS JavaScript事件循环机制

    区分进程和线程 进程是cpu资源分配的最小单位(系统会给它分配内存) 不同的进程之间是可以同学的,如管道.FIFO(命名管道).消息队列 一个进程里有单个或多个线程 浏览器是多进程的,因为系统给它的进 ...

  2. 浏览器中 JS 的事件循环机制

    目录 事件循环机制 宏任务与微任务 实例分析 参考 1.事件循环机制 浏览器执行JS代码大致可以分为三个步骤,而这三个步骤的往复构成了JS的事件循环机制(如图). 第一步:主线程(JS引擎线程)中执行 ...

  3. Node.js:事件循环

    ylbtech-Node.js:事件循环 1.返回顶部 1. Node.js 事件循环 Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高. Node.js 的每一个 ...

  4. Node.js 的事件循环机制

    目录 微任务 事件循环机制 setImmediate.setTimeout/setInterval 和 process.nextTick 执行时机对比 实例分析 参考 1.微任务 在谈论Node的事件 ...

  5. js的事件循环绑定和jQuery的隐式迭代

    js的事件循环绑定和jQuery的隐式迭代 js事件循环绑定 jQuery隐式迭代 先举一个例子:给定一个ul,点击列表内的每一个li元素,使它的背景色变红,下边分别用js代码和jQuery实现. & ...

  6. js的事件循环和任务队列

    js 异步.栈.事件循环.任务队列 在开发中经常遇到js的异步问题,为了方便理解,记录下来,随时回顾. 以下的所有代码都是在浏览器环境下运行 在浏览器中js的运行是依赖浏览器js引擎来解析的,并且是在 ...

  7. JS:事件循环机制、调用栈以及任务队列

    点击查看原文 写在前面 js里的事件循环机制十分有趣.从很多面试题也可以看出来,考察简单的setTimeout也就是考察这个机制的. 在之前,我只是简单地认为由于函数执行很快,setTimeout执行 ...

  8. js的事件循环机制和任务队列

    上篇讲异步的时候,提到了同步队列和异步队列的说法,其实只是一种形象的称呼,分别代表主线程中的任务和任务队列中的任务,那么此篇我们就来详细探讨这两者. 一.来张图感受一下 如果看完觉得一脸懵逼,请继续往 ...

  9. js的事件循环机制:同步与异步任务(setTimeout,setInterval)宏任务,微任务(Promise,process.nextTick)

    javascript是单线程,一切javascript版的"多线程"都是用单线程模拟出来的,通过事件循环(event loop)实现的异步. javascript事件循环 事件循环 ...

  10. JavaScript之JS单线程|事件循环|事件队列|执行栈

    本博文基于知乎"JavaScript作用域问题?"一问,而引起了对JavaScript事件循环和单线程等概念与实践上的研究.深入理解. 一.概念 0.关键词:JavaScript单 ...

随机推荐

  1. 实现atoi

    1. 去掉首位空格 2. 判断首位是否有正负号 3. 判断各位是否是0~9,有其他字符直接返回当前结果   public class Solution { public int atoi(String ...

  2. [Git] 007 三棵树以及向本地仓库加入第一个文件

    1. "三棵树" 1.1 前言 理论上要稍稍复杂一点 我在这里说得简化一点 顺道挖个坑 下回具体介绍 坑号编码:Git07-1 1.2 看图 1.3 简介 树左:工作区(平时写代码 ...

  3. [19/05/07-星期二] JDBC(Java DataBase Connectivity)_CLOB(存储大量的文本数据)与BLOB(存储大量的二进制数据)

    一. CLOB(Character Large Object ) – 用于存储大量的文本数据 – 大字段有些特殊,不同数据库处理的方式不一样,大字段的操作常常是以流的方式来处理的.而非一般的字段,一次 ...

  4. WOJ#3836 Sightseeing Trip

    描述 给定一张无向图,求图中一个至少包含 3 个点的环,环上的节点不重复,并且环上的边的长度之和最小.该问题称为无向图的最小环问题.在本题中,你需要输出最小环的方案,若最小环不唯一,输出任意一个均可. ...

  5. docker网络 macvlan

    docker 还开发了另一个支持跨主机容器网络的 driver:macvlan. macvlan 本身是 linxu kernel 模块,其功能是允许在同一个物理网卡上配置多个 MAC 地址,即多个 ...

  6. jsp:include 通过变量作为路径动态引入

    语法:<jsp:include page="<%=整体是个变量%>" flush="true"/> 示例: <%@ page la ...

  7. EF添加关联的提示问题:映射从第 260 行开始的片段时有问题:

    一,EF添加关联的提示问题 严重性 代码 说明 项目 文件 行 禁止显示状态错误 错误 3004: 映射从第 260 行开始的片段时有问题:没有为 设置 T_xx_xxRelation 中的属性 T_ ...

  8. JVM虚拟机基础知识

    1. Java的发展 Java之父:詹姆斯·高斯林 2. Java的技术体系 Java 程序设计语言 JVM class文件格式 编译器 Java API 第三方Java类库 三个版本: Java S ...

  9. Linux时间命令date

    date:打印当前时间 date "+定制信息":自定义格式打印时间 - date "+%H":打印当前时间的小时数 - date "+%H%M%S& ...

  10. jQuery学习总结05-事件

    1.事件的发生 <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...