1.异步

程序中现在运行的部分和将来运行的部分之间的关系是异步编程的核心。

多数JavaScript开发者从来没有认真思考过自己程序中的异步到底是如何出现的,以及为什么会出现,也没有探索过处理异步的其他方法。一直以来,低调的回调函数就算足够好的方法了。目前为止,还有很多人坚持认为回调函数完全够用。

但是,作为在浏览器、服务器以及其他能够想到的任何设备上运行的一流编程语言,JavaScript面临的需求日益扩大。为了满足这些需求,JavaScript的规模和复杂性也在持续增长,对异步的管理也越来越令人痛苦,这一切都迫切需要更强大、更合理的异步方法。

1.1 分块的程序

现在我们发出一个异步Ajax请求,然后在将来才能得到返回的结果(通过使用回调函数)。

//ajax(...)是某个库中提供的某个Ajax函数。
ajax("http://some.url.1",function myCallbackFunction(data){
console.log(data);//得到一些数据
});
function now(){
return 21;
} function later(){
answer = answer * 2;
console.log("Meaning of life: ", answer);
} var answer = now(); setTimeout(later, 1000);//Meaning of life: 42

setTimeout(...)设置了一个事件(定时)在将来执行,所以函数later()的内容会在之后的某个时间(从现在起1000毫秒之后)执行。

任何时候,只要把一段代码包装成一个函数,并指定它在响应某个事件(定时器、鼠标点击、Ajax响应等)时执行,你就是在代码中创建了一个将来执行的块,也由此在这个程序中引入了异步机制。

1.2 事件循环

现在我们来澄清一件事情(可能令人震惊):尽管你显然能够编写异步JavaScript代码,但直到最近(ES6),JavaScript才真正内建有直接的异步概念。

JavaScript引擎并不是独立运行的,它运行在宿主环境中,对多数开发者来说通常就是Web浏览器。经过最近几年的发展,JavaScript已经超过了浏览器的范围,进入了其他环境,比如通过像Node.js这样的工具进入服务器领域。实际上,JavaScript现如今已经嵌入到了从机器人到电灯泡等各种各样的设备中。

所有这些环境都提供了一种机制来处理程序中多个块的执行,且执行每个块时调用JavaScript引擎,这种机制被称为事件循环

ES6中Promise对事件循环队列的调度运行能够直接进行精细控制。

1.3 并行

异步是关于现在和将来的时间间隙,而并行是关于能够同时发生的事情。

var a = 20;

function foo(){
a = a + 1;
} function bar(){
a = a * 2;
} ajax("...",foo);
ajax("...",bar);

由于JavaScript的单线程特性,foo()bar()中的代码具有原子性。也就是说,一旦foo()开始运行,它的所有代码都会在bar()中的任意代码运行之前完成,或者相反。这称为完整运行特性

1.4 并发

两个或多个“进程”同时执行就出现了并发。这里的“进程”之所以打上引号,是因为这并不是计算机科学意义上的真正操作系统级进程。这是虚拟进程,或者任务,表示一个逻辑上相关的运算序列。

1.5 任务

在ES6中,有一个新的概念建立在事件循环队列之上,叫作任务队列。这个概念给大家带来的最大影响可能是Promise的异步特性。

事件循环队列类似于一个游乐园游戏:玩过了一个游戏之后,你需要重新到队尾排队才能再玩一次。而任务队列类似于玩过了游戏之后,插队接着继续玩。

2.回调

回调是编写和处理JavaScript程序异步逻辑的最常用方式。

回调函数是JavaScript的异步主力军,并且它们不辱使命地完成了自己的任务。

2.1 continuation

//A
ajax("...",function(data){
//C
});
//B

//A//B表示程序的前半部分,而//C标识了程序的后半部分。前半部分立刻执行,然后是一段时间不确定的停顿。在未来的某个时刻,如果Ajax调用完成,程序就会从停下的位置继续执行后半部分。

信任的问题

//C会延迟到将来发生,并且在第三方的控制下。我们把这称为控制反转,也就是把自己程序一部分的执行控制交给某个第三方。在你的代码和第三方工具之间有一份并没有明确表达的契约。

//过分信任输入
function addNumbers(x,y){
return x + y;
} addNumbers(21,21);//42
addNumbers(21,"21");//"2121"
//针对不信任输入的防御性代码
function addNumbers(x,y){
if(typeof x != "number" || y != "number"){
throw Error("Bad parameters");
}
return x + y;
} addNumbers(21,21);//42
addNumbers(21,"21");//Error: "Bad parameters"
//依旧安全但更好一些
function addNumbers(x,y){
x = Number(x);
y = Number(y); return x + y;
} addNumbers(21,21);//42
addNumbers(21,"21");//42

3.Promise

通过回调表达程序异步和管理并发的两个主要缺陷:缺乏顺序性和可信任性。

我们用回调函数来封装程序中的continuation,然后把回调交给第三方,期待其能够调用回调,实现正确的功能。通过这种形式,我们要表达的意思是:“这是将来要做的事情,要在当前的步骤完成之后发生”。

如果我们不把自己程序的continuation传给第三方,而是希望第三方给我们提供了解其任务何时结束的能力,然后我们自己的代码来决定下一步做什么。这种范式就称为Promise

绝大多数JavaScript/DOM平台新增的异步API都是基于Promise构建的。

相关阅读:看这一篇就够了!浅谈ES6的Promise对象

4.生成器

我们把注意力转移到一种顺序、看似同步的异步流程控制表达风格。使这种风格成为可能的“魔法”就是ES6生成器(generator)

4.1 打破完整运行

var x = 1;

//下面是生成器函数
function *foo(){
x++;
yield;//暂停点
console.log("x: ",x);
} function bar(){
x++;
} var it = foo();//构造迭代器 it.next();//启动foo()
x;//2
bar();
x;//3
it.next();//x: 3

注意:function* foo(){...}function *foo(){...}是一样的,唯一区别是*位置的风格不同。function*foo(){...}(没有空格)也一样,这只是风格偏好问题。

上述代码的运行过程:

  1. it = foo()运算并没有执行生成器*foo(),而只是构造了一个迭代器(iterator),这个迭代器会控制它的执行。
  2. 第一个it.next()启动了生成器*foo(),并运行了*foo()第一行的x++
  3. *foo()yield语句处暂停,在这一点上第一个it.next()调用结束。
  4. 我们查看x的值,此时为2。
  5. 我们调用bar(),它通过x++再次递增x。
  6. 我们再次查看x的值,此时为3.
  7. 最后的it.next()调用从暂停处恢复了生成器*foo()的执行,并运行console.log(...)语句,这条语句使用当前x的值3。

相关阅读:知乎上关于生成器的解释

4.2 生成器+Promise

ES6中最完美的世界就是生成器(看似同步的异步代码)和Promise(可信任可组合)的组合。

获得Promise和生成器最大效用的最自然的方法就是yield出来一个Promise,然后通过这个Promise来控制生成器的迭代器。

推荐阅读:ECMAScript 6 入门

参考资料:《你不知道的JavaScript》(中卷) 第二部分 异步和性能

JS的异步的更多相关文章

  1. 【译】深入理解python3.4中Asyncio库与Node.js的异步IO机制

    转载自http://xidui.github.io/2015/10/29/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3python3-4-Asyncio%E5%BA%93% ...

  2. js的异步加载你真的懂吗

    面试高频之js的异步加载 讲这个问题之前, 我们从另一个面试高频问题来切入, 我们的web页面从开始解析到页面渲染完成都经历了什么 ?  1  ,  创建document对象, 开始解析页面,    ...

  3. js的异步和单线程

    最近,同事之间做技术分享的时候提到了一个问题"js的异步是另开一个线程吗?"当时为此争论不休.会后自己查阅了一些资料,对这个问题进行一个自我的分析与总结,有不同意见的希望可以赐教, ...

  4. 探秘JS的异步单线程

    对于通常的developer(特别是那些具备并行计算/多线程背景知识的developer)来讲,js的异步处理着实称得上诡异.而这个诡异从结果上讲,是由js的“单线程”这个特性所导致的. 我曾尝试用“ ...

  5. JS实现异步提交

    什么是XMLHttpRequest? XMLHttpRequest对象用于在后台与服务器交换数据 XMLHttpRequst的作用 在不重新加载页面的情况下更新网页 在页面已加载后从服务器请求数据 在 ...

  6. JS的异步世界

    前言 JS的异步由来已久,各种异步概念也早早堆在开发者面前.可现实代码中,仍然充斥了各种因异步顺序处理不当的bug,或因不好好思考,或因不了解真相.今天,就特来再次好好探索一番JS的异步世界. 01 ...

  7. JS的异步模式

    JS的异步模式:1.回调函数:2.事件监听:3.观察者模式:4.promise对象 JavaScript语言将任务的执行模式可以分成两种:同步(Synchronous)和异步(Asychronous) ...

  8. Node.js之异步编程

    > 文章原创于公众号:程序猿周先森.本平台不定时更新,喜欢我的文章,欢迎关注我的微信公众号. ![file](https://img2018.cnblogs.com/blog/830272/20 ...

  9. js 同步 异步 宏任务 微任务 文章分享

    分享一篇 写的很好的 宏任务 微任务  同步异步的文章 文章原地址: https://juejin.im/post/59e85eebf265da430d571f89 这一次,彻底弄懂 JavaScri ...

  10. co.js - 让异步代码同步化

    近期在全力开发个人网站,并且又沉淀了一些前后端的技术.近期会频繁更新. 这篇文章首发于我的个人网站:听说 - https://tasaid.com/,建议在我的个人网站阅读,拥有更好的阅读体验. 这篇 ...

随机推荐

  1. 木马分析出现python语言,360的安全人员不禁感叹还有这种操作?

    几年前,敲诈者木马还是一个默默无闻的木马种类.然而,由于其极强的破坏力和直接且丰厚的财富回报,敲诈者木马这几年已经一跃成为曝光率最高的木马类型——甚至超越了盗号木马.远控木马.网购木马这传统三强.与此 ...

  2. shell解析ini格式文件

    功能 本脚本实现了ini文件中的查询修改指定value 百度云连接地址 链接:https://pan.baidu.com/s/12_T5yST7Y3L1H4_MkVEcvA 密码:fo5p 解压后先看 ...

  3. 云计算时代,传统企业 IT 从业者如何做好转型?

    本文来源于国外社区 DZone,作者 Dennis O'Reilly 撰写过多篇关于云计算.混合云等内容的文章,本文内容围绕云计算时代,企业纷纷上云,传统 IT 从业者如何做好转型. 本文由“数梦工场 ...

  4. python实现简单线性回归

    之前推导了一元线性回归和多元线性回归,今天就用python来实现一下一元线性回归 先看下之前推导的结果   ,  第一种是用循环迭代的计算方法.这里的x,y是numpy中的array类型 def su ...

  5. export命令详解

    基础命令学习目录首页 export 的基本作用就是将父shell中的局部变量设置为环境变量,使得该变量可以在子shell中使用.下面设置两种情景对export进行原理解析. 情景  1. 有一个名为m ...

  6. [linux] lsyncd同步工具

    环境说明: 192.168.56.101 同步源 192.168.56.102 同步目标 操作系统centos 7 lsyncd项目地址:https://github.com/axkibe/lsync ...

  7. PHP中你应该知道的require()文件包含的正确用法

    以前看一些PHP框架源码的时候,很奇怪在文件包含的时候,会用dirname(__FILE__)来拼凑文件路径,不知道这样做有什么好处,后来终于发现了其中的缘由. 我们来看一个简单的例子: 有a,b,c ...

  8. wordpress登录密码框明文显示最后一个输入的字符

    wordpress登录密码框明文显示最后一个输入的字符 (function(a){a.fn.dPassword=function(c){var e={interval:200,duration:100 ...

  9. ModelAndView在页面上取值时value="{contextConfigLocation=<NONE>}"

    后台: mv.getModel().put("initParam", 1); 页面: <input type="hidden" id="init ...

  10. 20162325 金立清 S2 W5 C14

    20162325 2017-2018-2 <程序设计与数据结构>第5周学习总结 关键内容摘要 集合是收集并组织其他对象的对象 集合中的元素一般由加入集合的次序或元素之间某些固有的关系而组织 ...