日期:2014-05-16  浏览次数:20378 次

JavaScript 中的异步梳理(3)——使用 Wind.js

拖了几百年的三部曲终于迎来了第三篇,时过境迁,Jscex 已经更名为 wind.js 了,这里先给一下之前的链接

  1. JavaScript中的异步梳理(1)——使用消息驱动
  2. JavaScript中的异步梳理(2)——使用 Promises/A

在之前介绍的方法中,无论是消息驱动还是 Promise,都无法摆脱「回调」这个东西。

习惯了命令式编程的我们似乎很难接受回调,因为它的执行顺序和代码编写顺序并不一致。 而 JavaScript 中的回调之所以会有这么多话题值得讨论,我想一方面是因为它有一张长得像 Java 的脸,而同时却又有如此多的异步特性。 反观像 Erlang, F# 那样生来就是异步的语言,似乎反而没这么多话题好讨论的。

异步就要回调吗?这是个问题,习惯了 JavaScript 中的异步似乎这个问题的答案是肯定的,但 Wind.js 却扭转了这一点。

在同步、阻塞的环境下,我们写下如下代码

str = readFile('...');
str += 'ok';
writeFile('...');

似乎理所当然地就认为 1、3 两行耗时操作会阻塞掉程序,于是在开发 GUI 程序的时候,遇到 IO 操作我们通常会开启新的线程来进行 IO, 然后完成时再通知主线程,这样可以避免GUI失去响应。

在 JavaScript 的世界里,用户代码只有一个线程,JS 使用异步来解决这个矛盾,与此同时使用回调的方式来达到「通知主线程」的效果。

似乎由于在此之前异步为人重视程度不是很高,JS 的异步特性被大家广为接受之后,似乎回调成为了标准的异步解决方案。 的确,回调是一种看起来很像声明的编程方法,在单一异步操作的时候,回调还算优雅,但一旦涉及异步流程控制的时候,回调嵌套就会成为挥之不去的噩梦。

回过头来看过去的同步阻塞编程方法,似乎顺序执行更讨好一些,因为代码怎么写的,程序顺序就是怎么样。

老赵开发的?Wind.js?为我们提供了「顺序编写、异步执行」的机会。 Wind.js 的原名叫 Jscex,全称 JavaScript Computation Expression,即 JavaScript 计算表达式。

计算表达式这个词是从函数式编程中来的,想象我们中学的时候解数学和物理题,我们总会用各种代数标识来表达变量,推导、化简完公式之后, 才把题目中给的具体数值代入。 这样做不仅让推导过程更加清晰可懂,还能避免中间的运算产生精度的损失。

在命令式编程中,我们写下

c = a + b;

的时候,a+b这个表达式就已经被执行计算,并且把结果赋值给?c?了。 但在函数式语言中则不尽然,由于「延迟计算」的特性,上面的代码并不一定会立即执行,而只有在它「需要被执行」(例如输出)的时候才会真正执行。