JavaScript是单线程单并发语言

单线程:主程序只有一个线程,即同一时间片段内其只能执行单个任务。

引发的问题:

单线程,意味着任务都需要排队,前一个任务结束,才会执行后一个任务。若前一个任务耗时很长,后一个任务就需要一直等待。导致IO操作耗时,但CPU闲置,造成性能浪费。

如何解决:

异步。主线程可以不管IO操作,暂时挂起处于等待中的任务,先运行排在后面的任务。等到IO操作返回了结果,再回过头,把挂起的任务执行下去。于是,所有任务可以分为两种,一种是同步任务,另一种是异步任务。

ps:当主线程阻塞时,任务队列仍然能被推入任务。

事件驱动程序模型基本的实现原理基本上都是事件循环Event Loop.

事件循环(Event Loop)

1.JavaScript内存模型:

调用栈(Call Stack):用于主线程任务的执行。

堆(Heap):用于存放非结构化的数据,譬如程序分配的变量与对象。

任务队列(Queue):用于存放异步任务与定时任务。

2.JavaScript代码执行机制:

所有同步任务都在主线程上的栈中执行,形成一个执行栈。

主线程之外,还存在一个“任务队列”。只有异步任务有了运行结果,就在“任务队列”之中放置一个事件,排队。

一旦“栈”中的所有同步任务执行完毕,系统就会读取“任务队列”,选择出需要首先执行的任务(由浏览器决定,并不按序),于是被读取的异步任务结束等待状态,进入执行栈,开始执行。

主线程不断重复第三步。

3.Event Loop

MacroTask(Task): 宏任务。setTimeout,setInterval, setImmediate,requestAnimationFrame,I/O,UI rendering;

MicroTask:微任务。process.nextTick(Node环境中),Promise,Object.observe(基本废弃),MutationObserver.

执行步骤:

执行宏任务(先进先出),一次循环只执行一个宏任务

执行栈:同步任务顺序执行,异步方法交给异步处理模块

执行栈为空时,取出微任务执行(先进先出),直到微任务队列为空

更新UI渲染。完成一轮循环,反复执行1-4步

渲染更新:

在一轮Event Loop中多次修改同一DOM,只有最后一次会进行绘制;

渲染更新会在Event Loop的tasks和microTasks完成后进行。但并不是每轮Event Loop都会更新渲染,浏览器有自己的机制来确定是否要更新渲染。如果在一帧(16.7ms)里多次修改DOM,浏览器只会渲染绘制一次。

如果希望每轮Event Loop都即时呈现变动,可以使用requestAnimationFrame

规范:

每个浏览器环境,至多由一个event loop。

一个event loop可以有1个或多个task queue,而仅有一个MicroTask Queue。

一个task queue是一列有序的task,每个task定义时都有一个task source,从同一个task source来的task必须放到同一个task queue,从不同源来的则被添加到不同的队列。

tasks are scheduled,所以浏览器可以从内部到JS/DOM,保证动作按序发生。

Microtasks are scheduled,Microtask queue在当前task queue的结尾执行。microtask中添加的microtask也被添加到Microtask queue的末尾并处理。

4.JS的运行环境:浏览器 & Node

浏览器中事件循环给予规范来实现。

Node是给予libuv这个库来实现的。

*JS是单线程执行的,而基于事件循环模型,形成了基本没有阻塞(除了alert或同步XHR等操作)的状态。

eg:

setTimeout(function(){

console.log(1);

});

new Promise(function(resolve){
console.log(2);
resolve();
}).then(function(){
console.log(3);
}); console.log(4);

执行结果:4 2 1 3

分析:

从宏任务队列(task)中取出script,将所有同步代码推入执行栈中执行,遇到异步代码交给异步处理模块,异步处理模块完成后按规则推入事件队列,宏任务推宏任务队列,微任务推微任务队列。所以输出2和4.

执行玩script中的同步代码,再将微任务队列中最老的任务推入执行栈执行,直到清空微任务。所以输出3;

浏览器更新渲染,再去宏任务队列中取出嘴来的任务推入执行栈中执行,循环以上步骤,所以输出1.

5.使用

在microtask中不要放置复杂的处理程序,防止阻塞UI的渲染;

可以使用process.nextTick处理一些比较紧急的事情。因为process.nextTick优先级高于其他微任务。

可以在setTimeout回调中处理上轮事件循环中UI渲染的结果;

注意不要滥用setInterval和setTimeout,它们并不能保证按时处理的。

一些可能会影响到UI的异步操作,可放在promise回调中处理,防止多一轮事件循环导致重复执行UI的渲染。

在Node中使用immediate来处理可能会得到更多的保证。

JavaScript中的事件循环的更多相关文章

  1. 深入理解javascript中的事件循环event-loop

    前面的话 本文将详细介绍javascript中的事件循环event-loop 线程 javascript是单线程的语言,也就是说,同一个时间只能做一件事.而这个单线程的特性,与它的用途有关,作为浏览器 ...

  2. JavaScript中的事件循环机制跟函数柯里化

    一.事件循环机制的理解 test();//按秒输出5个5 function test() { for (var i = 0; i < 5; i++) { setTimeout(() => ...

  3. 聊一聊JavaScript中的事件循环

    一.概念:事件循环 JavaScript是单线程的 1.整片 script 整体代码(第一个宏任务)放到执行栈中,执行之后,会触发很多方法 这些方法只能一个个的顺序执行,不能并发 2.这些要执行的方法 ...

  4. javascript 中的事件机制

    1.javascript中的事件. 事件流 javascript中的事件是以一种流的形式存在的. 一个事件会也有多个元素同时响应. 有时候这不是我们想要的效果, 我们只是需要某个特定的元素相应我们的绑 ...

  5. JavaScript中的事件对象

    JavaScript中的事件对象 JavaScript中的事件对象是非常重要的,恐怕是我们在项目中使用的最多的了.在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含这所有与事件有 ...

  6. JavaScript 进阶教程一 JavaScript 中的事件流 - 事件冒泡和事件捕获

    先看下面的示例代码: <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Jav ...

  7. 了解javascript中的事件(二)

    本文目录如下: 零.寒暄 一.事件的分类 二.事件代理 2.1 问题引出 2.2 什么是事件代理 2.3 完整示例 二.事件代理 三.事件代理思想的用处 四.总结 零.寒暄 这篇博客本该出现在两个月以 ...

  8. javascript中onclick事件能调用多个方法吗

    Q: javascript中onclick事件能调用多个方法吗? A: 可以的,方法如下onclick="aa();bb();cc();"每个方法用“;”分号隔开就行了

  9. js实例分析JavaScript中的事件委托和事件绑定

    我们在学习JavaScript中,难免都会去网上查一些资料.也许偶尔就会遇到“事件委托”(也有的称我“事件代理”,这里不评论谁是谁非.以下全部称为“事件委托”),尤其是在查JavaScript的事件处 ...

随机推荐

  1. VS Ctrl + Shift + Q

    在VS中按 Ctrl + Shift + Q 可以快速查找 void OnCollisionStay  等方法. void OnCollisionStay(Collision collision) { ...

  2. 错误:子进程 已安装 pre-removal 脚本 返回了错误号 1

    解决办法 sudo rm /var/lib/dpkg/info/<package name>.*

  3. Android Studio中导入v4,v7和recyclerview-v7包的方法

    概述 Android Studio中新建工程中会默认导入v7的包,即在gradle中默认配置了com.android.support:appcompat-v7:x.x.x的依赖.但是不会默认为我们配置 ...

  4. redis 读写锁实现

    一 先搞清楚读写锁要做什么. 基本就是 读读不互斥,读写互斥,写写互斥.可重入. 关于redis读写锁,我写了一次之后,总觉得很怪,然后就上网看到大神的redisson了,果断借鉴一番. 二 读行为 ...

  5. jq回到顶部效果分析

    在浏览网页时,超出屏幕高度就会出现提上点击回到顶部的图标,点击即可回到页面顶部. 用到的知识点如下: 1.首先控制图标的显示和隐藏,先要获取浏览器的高度. var wHeight = $(window ...

  6. 文件夹选择之FolderBrowserDialog控件

    应用程序可能只允许用户选择文佳夹而非文件,例如在播放MP3时,用户可能把所有的MP3放在一个文佳夹内,在添加时,只要选择添加这个文佳夹,将会把在这个文件内的所有MP3添加的播放器里.在这里对播放器来说 ...

  7. Spring-cloud微服务 Eureka学习教程-分布式搭建EurekaServer、EurekaClient+Ribbon(中级)

    我们这里只有一台服务器,所以我们先仿集群搭建. 完整demo项目代码:https://github.com/wades2/EurekaDemo2 在这之前我们先分析分析Eureka相比其他注册中心的好 ...

  8. Dubbo分布式日志追踪

    使用dubbo分布式框架进行微服务的开发,一个大系统往往会被拆分成很多不同的子系统,并且子系统还会部署多台机器,当其中一个系统出问题了,查看日志十分麻烦. 所以需要一个固定的流程ID和机器ip地址等来 ...

  9. Hibernate课程 初探一对多映射5-3 Eclipse根据表反向生成实体类

    1 配置 项目右击==>properties==>project facets==>convert to faceted form...复选框选中java 和 jpa==>fu ...

  10. [QualityCenter]QC是什么?发展历程是怎样?

    QC,即Quality Center,是一个基于Web的测试管理工具.它可以组织和管理应用程序测试流程的所有阶段,包括制定测试需求.计划测试.执行测试和跟踪缺陷.此外,通过Quality Center ...