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. Mac入门--安装PHP扩展redis,swoole

    1 php7以下可以通过pecl安装PHP扩展 安装redis扩展 pecl install redis 安装swoole扩展 pecl install swoole 2 PHP7以上通过源码编译安装 ...

  2. web 前端1 拾遗

    1.整体布局 三个div header body footer 2.div的居中 width:980px margin:0 auto 3.内联标签 inline #内联 无法使用高度.宽度 block ...

  3. SQL的“增删改”

    结构语言分类 DDL(数据定义语言)  create  drop  alter   创建删除以及修改数据库,表,存储过程,触发器,索引.... DML(数据操作语言)   insert  delete ...

  4. jsp对象 指令 动作

    转载来源:https://blog.csdn.net/u010897406/article/details/49618413 jsp九大内置对象:1>out 向客户端输出数据,字节流.如out. ...

  5. 饿了吗开源组件库Element模拟购物车系统

    传统的用html+jquery来实现购物车系统要非常的复杂,但是购物车系统完全是一个数据驱动的系统,因此采用诸如Vue.js.angular.js这些框架要简单的多.饿了吗开源的组件库Element是 ...

  6. 年月日联动select下拉菜单

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. asp.net core2.1认证和授权解密

    来源:https://www.cnblogs.com/pangjianxin/p/9372562.html asp.net core2.1认证和授权解密 本篇文章翻译自:https://digital ...

  8. jQ:"对象不支持“first”属性或方法"IE内核下不兼容first()、chilrdren()方法的处理

    场景:需要查找某元素下的第一个子集,使用了如下语句: $("#left_1>tbody").find(".menuTr").first().addClas ...

  9. 1. AtomicInteger 、Unsafe 及 CAS方法的整理

    本文摘自: https://blog.csdn.net/fanrenxiang/article/details/80623884 http://ifeve.com/sun-misc-unsafe/ h ...

  10. mysql清空表数据并重置自增ID

    mysql清空表数据并重置自增ID: ## 查看mysql> select * from work_order_company;mysql> show create table work_ ...