/*
第一次调用run:
fn参数为:One
第二次调用run:
fn参数为:One
yield返回值为:Two
调用yield,run返回:yield
fn运行完成,run返回:return
*/
从上面例子中,可以很明显看出 yield的使用方法与现在的javascript的语法相当不同。在别的语言中(C#、Python等)已经实现了 yield关键字,作为迭代器的中断。不妨在node上也实现一个迭代器,具体体会一下 yield的使用。还是以开头的斐波那契数列为例:
复制代码 代码如下:
var fiboGenerator = function () {
var a = 0, b = 0;
while (true) {
if (a == 0) {
a = 1;
Fiber.yield(a);
} else {
b += a;
b == a ? a = 1 : a = b - a;
Fiber.yield(b);
}
}
}
var f = new Fiber(fiboGenerator);
f.next = f.run;
for (var i = 0; i < 10; i++) {
console.log(f.next());
}
输出为:
复制代码 代码如下:
/*
1
1
2
3
5
8
13
21
34
55
*/
有两个问题需要留意,第一, yield说是方法,更多地像关键字,与 run不同, yield不需要依托Fiber实例,而 run则需要。如果在Fiber内部调用 run,则一定要使用: Fiber.current.run();第二, yield本身为javascript的保留关键字,不确定是否会、何时会启用,所以代码在将来可能会面临变更。
5.Fiber.prototype.reset():
我们已经知道Fiber可能存在不同的时态,同时会影响 run的行为。而 reset方法则不管Fiber处理什么状态,都恢复到初始状态。随后再执行 run,就会重新运行 fn。
6.Fiber.prototype.throwInto(Exception):
本质上 throwInto会抛出传给它的异常,并将异常信息作为 run的返回值。如果在Fiber内不对它抛出的异常作处理,异常会继续冒泡。不管异常是否处理,它会强制 yield,中断Fiber。
future库的使用
在node中直接使用Fiber并不一直是合理的,因为Fiber的API实在简单,实际使用中难免会产生重复冗长的代码,不利于维护。推荐在node与Fiber之间增加一层抽象,让Fiber能够更好地工作。 future库就提供了这样一种抽象。 future库或者任何一层抽象也许都不是完美的,没有谁对谁错,只有适用不适用。比如, future库向我们提供了简单的API能够完成异步转同步的工作,然而它对封装 generator (类似上面的斐波那契数列生成器)则无能为力。
future库不需要单独下载安装,已经包含在 fibers库中,使用时只需要 var future=require('fibers/future') 即可。
API
1.Function.prototype.future():
给 Function类型添加了 future方法,将function转化成一个“funture-function”。
复制代码 代码如下:
var futureFun = function power(a) {
return a * a;
}.future();
console.log(futureFun(10).wait());
实际上 power方法是在Fibel内执行的。不过现有版本的 future有bug,官方没有具体的说明,如果需要使用此功能,请删除掉 future.js的第339行和第350行。
2.new Future()
Future对象的构造函数,下文详细介绍。
3.Future.wrap(fn, idx)
wrap方法封装了异步转同步的操作,是 future库中对我们最有价值的方法。 fn表示需要转换的函数, idx表示 fn接受的参数数目,认为其 callback方法为最后一个参数(这边API的制定颇有争议,有人倾向传递 callback应该处于的位置,好在 wrap方法比较简单,可以比较容易修改代码)。看一个例子就能了解 wrap的用法:
复制代码 代码如下:
var readFileSync = Future.wrap(require("fs").readFile);
Fiber(function () {
var html = readFileSync("./1.txt").wait().toString();
console.log(html);
}).run();
从这个例子中可以看出Fiber异步转同步确实非常有效,除了语法上多了一步 .wait()外,其他已经 fs提供的 fs.readFileSync方法别无二致了。
4.Future.wait(futures):