JavaScript 异步编程-阿里云开发者社区

开发者社区> sp42> 正文

JavaScript 异步编程

简介: 异步编程 Async JavaScript 在 Node 面前获得前所未有的重视。本文结合 Trevor Burnham 所著 《Async JavaScript Build More Responsive Apps with Less Code(中文名: JavaScript 异步编程:设计快速响应的网络应用)》一书,梳理 JavaScript 的异步编程的方方面面。
+关注继续查看

异步编程 Async JavaScript 在 Node 面前获得前所未有的重视。本文结合 Trevor Burnham 所著 《Async JavaScript Build More Responsive Apps with Less Code(中文名: JavaScript 异步编程:设计快速响应的网络应用)》一书,梳理 JavaScript 的异步编程的方方面面。

为更好地了解异步开发的来龙去脉,我们先回顾一下 JS 服务端的历史,看到底解决了什么问题(当然是否真的解决是另外一个问题),并以此来与 Node 横向比较。

  • 早期出现的 Javascript 服务端:Netscape LiveWire,它将阻塞式 I/O包含在内,使用多进程模
  • 上世纪九十年代中期出现的 ASP,微软很给力,除了主流的 VBS 编程模式,还提供有基于 JScript 的。此时期到后来的 Aptana 的 Jaxer 也是没有突破旧的同步模式
  • 2009 年,Node 问世了,其特点:异步、非阻塞、高并发。这里说明一下,“异步”、“非阻塞”、“高并发”三者之间的关系可以说是一层一层递进的

实现异步的关键,简单讲,在于“闭包(Closures)”。函数是 JS 为第一等公民,可以把函数作为对象调来调去,并一个函数轻易地包含另外一个函数;或者被另外一个函数包含着,也没有问题。——故所以,在 JS 里面闭包是天然支持的。从泛语言的角度讲,任何有闭包的语言都是函数式语言,区别在于写起来是否轻松,越轻松的话那么越名副其实。这样的话,JS 具备了那么多优点,如果把 JS 应用在非阻塞环境,例如 Socket 网络编程中,是否可行呢? Node 作者 Ryan Dahl 就是这样的想的,于是尝试将 V8 与 非阻塞的 C 代码结合起来,从而诞生了 Node。后来事实证明,Ryan 的方式不仅可行且表现不俗。

综合几个方面,我们不妨再思考下这些问题:

  1. 异步编程、事件模型、事件队列、阻塞/非阻塞、异步函数/回调函数……等等,这一堆名词有神马区别与联系?假设我们要以此进行苦逼的考试,这势必将是一堆名称解析的题型:(
  2. 如果我们是从前端过来的,怎么发现前端没有“大谈特谈”异步编程,这又是为何?
  3. 到底 JS 怎么实现异步编程?最朴素的 JS 底层机制究竟是怎样的?
  4. 更重要的,我的 异步 JS 应该怎么写法好?

实际上,包括 JAVA 在内的许多 API 如 JDK 都提供 NIO 非阻塞版本之接口。如果使用多线程模型编码,面临着若干问题。先着眼于两点:

  • 线程是贵重的。在一定环境下,使用线程的数量是有限制的。
  • 为保证数据的线程安全性,需要调用互斥量或者信号量来封装数据。这将增加我们代码的复杂性。

多线程模型下固然同样可以处理非阻塞调度,只是相比事件模型消耗的资源来得更大,尤其长连接的场景,最能体现这种不足。另外编码成本也更高。关于两者的分析,小弟在旧文已经探讨过,详见《学习NodeJS第二天:漫谈NodeJS 》

前端没有“大谈特谈”异步编程

实际上,不论前端抑或后端,都会遭遇一个问题,就是如何优雅应对复杂事件集的范畴,这仍属于 JavaScript 有待解决的前沿领域。

历史与当前总结

从1995 年诞生的年份开始起,本属“草根”到不得了的 JavaScript 于 AJAX 革命成功之后“颠覆性”地一路走来并在茁壮地成长,除了 VB Script 正面较量外,其他的 RIA 应用还不算有真正的威胁,Flash、Sliverlight、Java Fx 你方唱罢我登台,对 JavaScript 倒也可算“小打小闹”。

不管怎么样,JavaScript 就坚守在浏览器的阵地。Google Gmail 之于 JavaScript 所倚重的力量有目共睹,于是数以百计的项目纷纷把 JavaScript 派上前端。这一热潮更是催生了 JS Runtime 之竞争态势,Apple 的 Safari/Webkit、Mozilla 的 Firefox OS、连微软的 Metro 界面开发都把 HTML5 置于与 C#、VB 平起平坐的地位。

若说语言有生涯,这便是 JavaScript 生涯中的第一个转折点。

渐渐地,JavaScript 成为一门体面的语言。这固然与原发明者出色的设计理念有关;更重要的是,拜无处不在的浏览器所赐——JavaScript 比任何语言都有资格兑现了 Java 那古老的承诺“一次编写、到处运行”。

然而,没有下一站“给力”的开发潮流,恐怕一切美好都是“虚火”,不足以让人们把视野关注在 JavaScript 身上。如果把 JavaScript 比作一个男人,他会有第二个转折点吗?

不如将 JavaScript 真正可应用于服务端编程,岂不是更好!?这种全端的开发模式不用说也是顺理成章的。

——恰好,Node 出现了。

关于 Node 本身的优点已经铺天盖地了,不想多分析,但要探讨的是,Node 之出现对于 JavaScript 的“利导”不见得也是一帆风顺的。

JavaScript 设计的初衷是为了强化 Netscape 浏览器的展现能力,仅仅是脚本之目的。不曾想,现在业已成为多媒体、多任务、多内核网络世界中一员,然而微妙的却是,JavaScript 并没有摇身一变成为支持多线程的语言(也许随着语言规范的发展也会加入),而是稳固单线程的一门语言(早已超出脚本,可称为语言了,或者界限已经模糊了)。

下面我们花大量篇幅来介绍扫服务端事件驱动开发的概念。理解这些概念是实践 JS 异步编程的关键。

关于 JS 的一些认识

在许多语言中,事件模型不属于语言级别的支援,而是由外层 API 提供。但 JS 事件一直是语言的核心;

前面已经提到,JS 对闭包天然的支持。这姑且不以晦涩的闭包概念深入原理,只是明白

引入线程的概念是为了“并行”,可以处理多个任务同时开始,同时执行,同时进行,从而整体上加快最终效率。多个线程对应多项任务,多个对多个的分工这很好理解。但我们知道, Node JS 始终是单线程程序,却怎么运行多个任务,而且效率反而高?——这怎么说?实际上,我要告诉大家三点,1)JS 的确同一时间内只会做一件事,这是所谓单线程的表现;2)那岂不是同步意思了,难道不能并行了吗?但没关系,且看;3)我们把 JS 设计为一个“圈 Loop”,一个可以永远(当然也可以手工或者强行中止的)运行下去的循环,同时这个循环结构上是个队列,允许你不断往这个队列加入新任务。如果发现处理完毕的事件,则从队列中剔除表示执行完毕;如果没处理完毕,嗯~这个循环看了看之后不做什么,继续走下去不停留。又因为是循环的缘故,尚未完成的任务又会被事件机制访问,直到执行完毕为止。如此便可以把多个任务“不落单”地处理完毕。

是不是到这里,问题就完了?不对~感觉多任务执行如何哪里,你始终还没有说清楚,对不对?

嗯,能够提出深入的发问很好。尽管我没有挖据 V8 & Linux 代码去论证,但相信凭借我的自圆自说,个中的原理是这样的:

  • JS 再一次成为了接口语言,在 Node V8 里面封装了 C/C++ 底层,呈现一套以 JS 语法的 API。但实际运算仍交到 C/C++ 执行;
  • 假设这些任务都需要一定的耗时来完成,也就是说,使用异步的场景是适合的;
  • 使用 Node 不等于你程序跑起来就是纯粹的单线程程序,得从微观角度观察;
  • 因为 JS 不允许同时多个任务,但底层的 C/C++ 可以,于是底层运行着的是多个线程,因此多个任务同时运行成为可能。
  • 事件队列中既可以是 JS 闭包,也是可以是系统的调用。

虽然 JS 初始化了底层去执行任务,但 JS 并不干涉任务的过程,不关心任务怎样完成,他只需要知道最终结果,ok (触发用户成功的回调)还是不 ok(触发 err 事件)。JS 知不知道这些多个线程存在?当然知道,但决不会把它们暴露出来,而是自己“事件循环”的机制来调度。你可以把 JS 这一层面想象为一个指挥者、总的调度者,它催生了多个任务同时跑,然后经常不辞劳苦地围着任务列表(即“事件队列”)在转,一个一个挨着问,“搞定没有”?“没有吗?”,“没有,在弄呢”,“好,我不催你”,继续访问下家……周而复始。这个过程中,系统事件内部是有多线程在跑的。只是我们不晓得而已,我们看到的只是 JS 层面的机制。这固然是 Node 优雅的地方,也是其卖点所在:不用线程却能操控多任务。也许不了解的人以为这是 JS 的“魔法”所赐,但无论如何形容,我们的任务就是要摸清楚这套 JS 机制,为我所用。

若要以线程称呼 JS,那么 JS 便是单线程程序。但有没有多线程的 JS?有!更确切地说,你可以在你程序中让多线程参与进来,但 JS 基本单元就只是一条线程。未来 JS 语言规范会出现线程处理的关键字,不是没有这种可能。但现在 JS 单线程模型是简单的、朴素的、友好的。当然有许多方式为你的 JS 程序提供多线程的支持。下面我们也分别进行介绍。假设不借助其他手段,一个 JS 程序有且只有一个事件循环队列。

var start = new Date;
setTimeout(function(){
    var end = new Date;
    console.log('Gone:', end -start, 'ms');
}, 200);
// alert(11)
while((new Date - start) < 1000){} // 强行阻塞 
// alert(33)
……未完待续……

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
JavaScript 异步编程
异步编程 Async JavaScript 在 Node 面前获得前所未有的重视。本文结合 Trevor Burnham 所著 《Async JavaScript Build More Responsive Apps with Less Code(中文名: JavaScript 异步编程:设计快速响应的网络应用)》一书,梳理 JavaScript 的异步编程的方方面面。
635 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
9987 0
JavaScript 编程精解 中文第三版 九、正则表达式
九、正则表达式 原文:Regular Expressions 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 部分参考了《JavaScript 编程精解(第 2 版)》 一些人遇到问题时会认为,“我知道了,我会用正则表达式。
1151 0
JavaScript高级编程
         原文地址: http://www.onlamp.com/pub/a/onlamp/2007/07/05/writing-advanced-javascript.html        Web应用程序(Web Applications)        从计算机纪元的黎明刚刚来临开始,不同平台间软件的互用性就一直是关注的焦点。
637 0
JavaScript 编程精解 中文第三版 七、项目:机器人
七、项目:机器人 原文:Project: A Robot 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 部分参考了《JavaScript 编程精解(第 2 版)》 […] 置疑计算机能不能思考 […] 就相当于置疑潜艇能不能游泳。
976 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
13770 0
Javascript编程“陷阱”总结
javascript中有很多陷阱,现在来总结一下:
1435 0
JavaScript 编程精解 中文第三版 十二、项目:编程语言
十二、项目:编程语言 原文:Project: A Programming Language 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 部分参考了《JavaScript 编程精解(第 2 版)》 确定编程语言中的表达式含义的求值器只是另一个程序。
1092 0
温习javascript DOM编程
Code:              复习Dom操作              #newTest        {            color...
538 0
+关注
sp42
移动项目技术负责人。多年全栈经验,熟悉 Java 和 JS,CSDN 博客技术专家,著有《ExtJS 详解与实践》等书。
294
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载