1. Javascript的运行时模型——事件循环 
JS的运行时是个单线程的运行时,它不像其他编程语言,比如C++,Java,C#这些可以进行多线程操作的语言。当它执行一个函数时,它只会一条路走到黑,不会在当前函数结束之前去调用其他的函数(除非当前函数主动调用其他函数)。它也不用担心会有其他线程打扰它,因为它的运行时只有一个线程。如果你还记得一些计算机原理的话,这种运行时只有一个栈,设计起来相当的简单。

一条路走到黑的设计很棒,因为它足够简单,但是又是谁决定哪个函数从开始进入栈内执行呢?答案是JS的运行时还有一个事件等待队列与栈搭配,每当运行栈为空时(也就是当前函数运行结束),JS的运行时就从当前的事件队列中取出一个消息处理,执行与这个消息相关联的函数。这种行为可以用以下代码来说明:

 while (eventQueue.waitForMessage()) {
let event = eventQueue.pop();
let handler = event.handler;
handler(); //执行事件关联的函数
context.scheduler.schedule(); //让调度器处理一下其他事务
}

有了运行栈和事件队列之后,我们的Javascript运行时已经初具雏形。不过Javascript中的变量都是对象,它们的大小通常很大,可不是一个小小的栈能放下的,如果我们熟悉C++,就会知道一般在C++中我们只在栈中存储基本类型(int, bool等)和指针,而指针所指的位置是内存堆中的一个地址,这也是JS的对象的存储地点。下面这张图可以形象地解释一下JS运行时的模型。

2. 事件循环模型的优点和缺点 
先说优点。除了实现上的简单,Javascript的最大优点就是完全异步,永不阻塞。这句话可能有点令人迷糊,一个单线程的运行时怎么完全异步,永不阻塞?实际上虽然JS运行时单线程,但是浏览器是个多进程多线程的环境,这一个点在后端也一样,虽然Node是个单线程JS运行时,但是后端还有其他进程和线程配合Node一起完成响应操作。

以浏览器打开IndexedDB为例,当你执行indexedDB.open()的之后,当前的Javascript运行栈就结束了,JS可以处理其他事件的关联函数,所以JS不会阻塞。那原来的open操作交给谁了呢?浏览器会调用其他线程接管这个打开数据库的过程,当返回时,浏览器会在JS运行时的事件队列中添加一个打开成功或者打开失败的事件,同时将你当时添加的回调函数关联到事件。

再说缺点。我们都知道JS的调用函数只会一条路走到黑,而且没有正常的方法能打断这一过程,如果这一路恰好比较长(比如进行了大量的数学运算),就会使JS进入一种类阻塞的状态,页面会无法响应。等等!刚说JS永不阻塞,这里怎么又冒出一个类阻塞呢?这时因为我们所说的阻塞一般都是指IO阻塞,也就是CPU等IO结束的过程,这种情况在JS中可以永远不会发生(注意这里是可以,不是一定,某些IO操作是有同步的API可以调用的)。所谓类阻塞状态呢,就是在执行CPU密集型任务,这是一种不可避免的过程。那为什么这种情况下页面会没有响应呢?这时因为浏览器虽然会把事件放入事件队列里,但是由于前一个函数还没执行完,页面响应事件关联的函数得不到执行,自然页面会表现出不响应的状态。

3. Promise的实现 
Promise是JS处理回调的一种方式,也是利用JS的事件循环模型的一个编程范式包装,也是ES7中await async的基础。如果说回调是对JS事件模型最直接最拙劣的实现的话,Promise至少给回调加了件衣服,使它不再那么难看。但本质上讲,Promise还是描述JS事件循环模型的一种工具。下面给个例子来说明它和JS事件模型的联系。

 let getUrlAsync = (url) => {
let promise = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onload = () => resolve(xhr.responseText);
xhr.onerror = () => reject(xhr.statusText);
});
return promise;
};
getUrlAsync('http://exaple.com/text/11111')
.then(res => console.log(res))
.catch(error => console.log(error));

当调用getUrlAsync时,JS运行时做以下事情: 
1. 会创建一个Promise对象,此时还是在getUrlAsync的栈帧里; 
2. 然后创建一个XMLHttpRequest对象,此时还是在getUrlAsync的栈帧里; 
3. 调用XMLHttpRequestopen方法,此时浏览器其他线程接管open过程,JS无需等待open结束; 
4. 给xhronload事件关联一个处理函数(委托),注意此时该事件并没有进入事件队列; 
5. 给xhronerror事件关联一个处理函数(委托),同样此时该事件没有进入运行时的事件队列; 
6. 传入res => console.log(res)来具体化第4步中的委托; 
7. 传入error => console.log(error)来具体化第5部中的委托,此时当前的运行栈就退出了,运行时将处理其他事件。 
在某一个时刻,浏览器控制的open方法返回,它会在JS运行时的事件队列中添加一个事件,比如onload 
8. JS运行时循环到onload事件,并找到它的关联处理函数,在这个例子中就是res => console.log(res),并运行这个函数。

最后吐槽一个博客园,还不支持Markdown吗?默认编辑器真的好难用。。。。

Javascript的事件模型和Promise实现的更多相关文章

  1. 从JavaScript的事件循环到Promise

    JS线程是单线程运行机制,就是自己按顺序做自己的事,浏览器线程用于交互和控制,JS可以操作DOM元素, 说起JS中的异步时,我们需要注意的是,JS中其实有两种异步,一种是基于浏览器的异步IO,比如Aj ...

  2. 标准事件模型和IE事件模型有哪些区别?请具体解释他们的差异。

    通常,事件传送有三个阶段:事件捕获阶段,停留目标阶段,事件冒泡阶段. 1.阶段差异 DOM事件模型包含捕获阶段和冒泡阶段,DOM事件模型可使用e.stopPropagation()来阻止事件流:IE事 ...

  3. javascript绑定事件

    本质:不同的库或者工具中总是封装了不同的事件绑定形式,但是究其根源,还是IE事件模型和W3C事件模型不同的处理方式 1)W3C事件模型:支持事件捕捉和冒泡 addEventListener('type ...

  4. BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第9章节--client对象模型和REST APIs概览 JavaScript

    BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第9章节--client对象模型和REST APIs概览  JavaScript         与托管.NETclien ...

  5. Javascript知识——事件

    O(∩_∩)O~~又是新的一周开始了,今天还是在继续学习Javascript知识,今天主要讲了事件的知识.现在就总结下吧. 事件 事件一般是用于浏览器和用户操作进行交互.最早是 IE 和 Netsca ...

  6. JavaScript笔记——事件

    事件一般是用于浏览器和用户操作进行交互.最早是 IE 和 Netscape Navigator 中出现, 作为分担服务器端运算负载的一种手段.直到几乎所有的浏览器都支持事件处理.而 DOM2 级规范开 ...

  7. 网络知识学习1---(基础知识:ISO/OSI七层模型和TCP/IP四层模型)

    以下的内容和之后的几篇博客只是比较初级的介绍,想要深入学习的话建议自己钻研<TCP/IP详解 卷1:协议> 1.ISO/OSI七层模型    下四层是为数据传输服务的,物理层是真正的传输数 ...

  8. 系统间通信(5)——IO通信模型和JAVA实践 下篇

    7.异步IO 上面两篇文章中,我们分别讲解了阻塞式同步IO.非阻塞式同步IO.多路复用IO 这三种IO模型,以及JAVA对于这三种IO模型的支持.重点说明了IO模型是由操作系统提供支持,且这三种IO模 ...

  9. 异步IO模型和Overlapped结构

    .NET中的 Overlapped 类 异步IO模型和Overlapped结构(http://blog.itpub.net/25897606/viewspace-705867/) 数据结构 OVERL ...

随机推荐

  1. Java缓存相关memcached、redis、guava、Spring Cache的使用

    随笔分类 - Java缓存相关 主要记录memcached.redis.guava.Spring Cache的使用 第十二章 redis-cluster搭建(redis-3.2.5) 摘要: redi ...

  2. 10-28质量监控ELK

    监控业务范围 app崩溃监控(Bugly) 应用性能监控(APM) 业务监控(TalkingData.友盟) 质量监控(缺位) 质量监控平台ELK elk官网 数据构造 线上错误状态分布 故障影响范围 ...

  3. js 获取下一秒 时间

    function getNextTime(start){ //var start = '09:30:00'; var _s = new Date(); var startDate = _s.getFu ...

  4. 第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛-等式(求$N^2$的因子个数)

    一.题目链接 https://www.nowcoder.com/acm/contest/90/F 二.题面 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言655 ...

  5. java程序调优系列(一)intern()代替equal()

    1. 首先String不属于8种基本数据类型,String是一个对象. 因为对象的默认值是null,所以String的默认值也是null:但它又是一种特殊的对象,有其它对象没有的一些特性. 2. ne ...

  6. ggplot map

    ggplot {ggplot2} R Documentation Create a new ggplot Description ggplot() initializes a ggplot objec ...

  7. div+css 命名规则

    编写网页的时候,一般都没有把命名规则认真对待.在结合语义以及搜索优化两方面给出了一套命名方案,对增强阅读性.规范性和提高开发效率是有帮助的,当然,这方面的规范,仁者见仁智者见智,网上有许多前辈们以经验 ...

  8. WPF 后台添加DataGrid

    public DataGrid CreateDataGrid() { //自定义DataGrid DataGrid dataGrid = null; dataGrid = new DataGrid() ...

  9. 分享 - 普通程序员如何转向AI方向

    原作者:计算机的潜意识 原文链接,内容稍有改动,侵删 1. 目的2. AI领域简介3. 学习方法4. 学习路线 0) 领域了解1) 知识准备2) 机器学习3) 实践做项目4) 深度学习5) 继续机器学 ...

  10. 小学生作业V2.0

    211606320刘佳&211506332熊哲琛 一.预估与实际 PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Plann ...