[Effective JavaScript 笔记]第61条:不要阻塞I/O事件队列
js程序是构建在事件之上的。输入可能来自不同的外部源。在一些语言中,我们习惯地编写代码来等待某个特定的输入。
var text=downloadSync('http://example.com/file.txt');
console.log(text);
像这样的形式downloadSync称为同步函数(或阻塞函数)。程序会停止做任何工作,而等待它的输入。在这个例子中,也就是等待从网络上下载文件的结果。由于在等待下载完成的期间,计算机可以做其他有用的工作,因此这样的语言通常为程序员提供一种方法来创建多个线程,即并行执行子计算。它允许程序的一部分停下来等待(阻塞)一个低速的输入,而程序的另一部分可以继续进行独立的工作。
在js中,大多的I/O操作都提供了异步的或非阻塞的API。程序员提供一个回调函数,一旦输入完成就可以被系统调用,而不是程序阻塞在等待结果的线程上。
var text=downloadSync('http://example.com/file.txt',function(text){
console.log(text);
});
该API初始化下载进行,然后在内部注册表中存储了回调函数后立即返回,而不是被网络请求阻塞。当下载完成之后,系统会将下载完的文件的文本作为参数调用该已注册的回调函数。
随着事件的发生,事件被添加到应用程序的事件队列的末尾。js系统使用一个内部循环机制来执行应用程序。该循环机制每次都拉取队列底部的事件,以接收到这些事件的顺序来调用这些已经注册的js事件处理程序,并将事件的数据作为该事件处理程序的参数。
运行到完成机制担保的好处是当代码运行时,你完全掌握应用程序的状态。根本不必担心一些变量和对象属性的改变由于并发执行代码而超出你的控制。并发编程在js中往往比使用线程和锁的c++,java或c#更容易。
然而,运行到完成机制的不足是,实际上所有你编写的代码支撑着余下应用程序的继续执行。像浏览器这样的交互式应用程序中,一个阻塞的事件处理程序会阻塞任何将被处理的其他用户输入,甚至可能阻塞一个页面的渲染,从而导致页面失去响应的用户体验。在服务器环境中,一个阻塞的事件处理程序可能会阻塞将被处理的其他网络请求,从而导致服务器失去响应。
js并发的一个最重要的规则是绝不要在应用程序事件队列中使用阻塞I/O的API。在浏览器中,甚至几乎没有任何阻塞API是可用的,尽管有一些平台实现了。提供类似于downloadAsync功能的网络I/O的XMLHttpRequest库有一个同步的版本实现,被认为是不好的。对于web应用程序的交互性,同步的I/O会导致灾难性的后果,它在I/O操作完成之前一直会阻塞用户与页面的交互。
相比之下,异步的API用在基于事件的环境中是安全的,它们迫使应用程序逻辑在一个独立的事件循环“轮询”中继续处理。如上面的例子,假设需要几秒钟来下载网络资源,在这段时间里,数量庞大的其他事件很可能发生。在同步的实现中,这些事件就会堆积在事件队列中,而事件循环将停留等待该JS代码执行完成,这将阻塞任何其他事件的处理。在异步的版本中,JS代码注册一个事件处理程序并立即返回,这将在下载完成之前,允许其他处理程序处理这期间的事件。
在主应用程序事件队列不受影响的环境中,阻塞操作很少出问题。例如,web平台提供了Worker的API,该API使得产生大量的并行计算成为可能。不同于传统的线程执行,Workers在一个完全隔离的状态下执行,没有获取全局作用域或应用程序主线程web页面内容的能力。因此,它们不会妨碍主事件队列中运行的代码的执行。在一个Worker中,使用XMLHttpRequest同步的变种很少出问题。下载操作的确会阻塞Worker继续执行,但这并不会阻止页面的渲染或事件队列中的事件响应。在服务器端环境中,阻塞的API在启动一开始是没有问题的,也就是在服务器开始响应输入的请求之前。然后在处理请求期间,浏览器事件队列中存在阻塞的API就是有问题的啦。
提示
异步API使用回调函数来延缓处理代价高昂的操作以避免阻塞主应用程序
js并发地接收事件,但会使用一个事件队列按序地处理事件处理程序
在应用程序事件队列中绝不要使用阻塞的I/O
[Effective JavaScript 笔记]第61条:不要阻塞I/O事件队列的更多相关文章
- [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象
js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...
- [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符
“1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...
- [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码
函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...
- [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法
js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...
- [Effective JavaScript 笔记]第65条:不要在计算时阻塞事件队列
第61条解释了异步API怎样帮助我们防止一段程序阻塞应用程序的事件队列.使用下面代码,可以很容易使一个应用程序陷入泥潭. while(true){} 而且它并不需要一个无限循环来写一个缓慢的程序.代码 ...
- [Effective JavaScript 笔记]第62条:在异步序列中使用嵌套或命名的回调函数
异步程序的操作顺序 61条讲述了异步API如何执行潜在的代价高昂的I/O操作,而不阻塞应用程序继续处理其他输入.理解异步程序的操作顺序刚开始有点混乱.例如,下面的代码会在打印"finishe ...
- [Effective JavaScript 笔记]第67条:绝不要同步地调用异步的回调函数
设想有downloadAsync函数的一种变种,它持有一个缓存(实现为一个Dict)来避免多次下载同一个文件.在文件已经被缓存的情况下,立即调用回调函数是最优选择. var cache=new Dic ...
- [Effective JavaScript 笔记]第68条:使用promise模式清洁异步逻辑
构建异步API的一种流行的替代方式是使用promise(有时也被称为deferred或future)模式.已经在本章讨论过的异步API使用回调函数作为参数. downloadAsync('file.t ...
- [Effective JavaScript 笔记]第46条:使用数组而不要使用字典来存储有序集合
对象属性无序性 js对象是一个无序属性集合. var obj={}; obj.a=10; obj.b=30; 属性a和属性b并没有谁前谁后之说.for...in循环,先输出哪个属性都有可能.获取和设置 ...
随机推荐
- Cordova4.0 系列 -- 常用命令(2)
一. 创建一个cordova工程 create <directory> [<id> [<name>]] 二. 列出该工程支持哪些平台 platform [ls | ...
- [BZOJ2659][WC2012]算不出的算式(几何)
题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2659 分析:很巧的想法,原式的值就是y=q/p x这条直线的下面和左边的点的个数.处理 ...
- 第十章:Javascript子集和扩展
本章讨论javascript的集和超集,其中子集的定义大部分处于安全考虑.只有使用这门语言的一个安全的子集编写脚本,才能让代码执行的更安全.更稳定.ECMScript3标准是1999年版本的,10年后 ...
- keep_on _coding——js_good_parts
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Maven-本地安装
本文测试安装maven3 安装 Maven 之前要求先确定你的 JDK 已经安装配置完成.Maven是 Apache 下的一个项目,目前最新版本是 3.0.4,我用的也是这个. 首先去官网下载 ...
- Spring 常用注解
用注解来向Spring容器注册Bean.需要在applicationContext.xml中注册 <context:component-scan base-package=”pagkage1[, ...
- 图解Android - Android GUI 系统 (5) - Android的Event Input System
Android的用户输入处理 Android的用户输入系统获取用户按键(或模拟按键)输入,分发给特定的模块(Framework或应用程序)进行处理,它涉及到以下一些模块: Input Reader: ...
- 【UVALive 7334】Kernel Knights
题 题意 有两个队的骑士1到n和n+1到2n,每个骑士只能互相攻击对手队的一个骑士.kernel的意思是在这个kernel里的骑士不会互相攻击,在kernel外的骑士被kernel里的骑士攻击. 现在 ...
- 35.Android之带删除按钮EditText学习
今天实现Android里自定义带删除功能的EditText,效果如下: 当输入内容时,EditText变为带有一个删除功能按钮的编辑框,如图: 实现代码很简单,直接上代码, 布局文件xml: < ...
- 【poj1050】 To the Max
http://poj.org/problem?id=1050 (题目链接) 题意 求二维最大子矩阵 Solution 数据好像很水,N最大才100,N^4大暴力都可以随便水过. 其实有N^3的做法.枚 ...