媒介
在《ES6 异步编程之一:Generator》中完成了一个异步函数挪用链,它是一个顺序挪用链,很相似义务链情势,但实际每每不是平淡无奇的,更多的实际上是峰回路转,本文将继承议论更多Generator
的用法。
作为函数的Generator
在之前的示例中,我们更多的是把天生器作为一个迭代器来轮回挪用每一个函数,但无视了天生器也是个函数,意味着天生器内部可以完成庞杂的营业逻辑,以下的代码经由过程yield
守候文件读取效果并对效果举行特定的处置惩罚,
function* generator() {
let r1 = yield get('a');
if (r1) {
let r2 = yield get('b');
if (r2) {
console.log(yield get('d'));
}
} else {
console.log(yield get('c'));
}
}
let g = generator();
g.next();
假如get
是个异步挪用,以上的代码想要可以实行则须要get
函数实行获得效果后挪用天生器的next
要领来推动,这请求get
函数能持有天生器对象,这明显并不轻易。
偏函数
偏函数(Partial Function)是对函数定义域的子集定义的函数,情势上就是指定恣意部份参数天生一个新的函数,以下:
function sum(a, b, c) {
return a + b + c;
}
function sum1(a) {
return function(b, c) {
return a + b + c;
};
}
function sum2(a, b) {
return function(c) {
return a + b + c;
};
}
sum(1, 2, 3) == sum1(1)(2, 3); //true
sum(1, 2, 3) == sum2(1, 2)(3); //true
平常在设想异步挪用api时,我们老是声明一个参数来吸收回调函数,当和偏函数相结合就变成如许:
function get(f, callback) {
delay(100, function(s) {
callback(s + ':get ' + f);
});
}
get('a', func); //挪用get时必需马上传入一个函数
//转换成偏函数情势:
function partialGet(f) {
return function(callback) {
delay(100, function(s) {
callback(s + ':get ' + f);
});
};
}
let pGet = partialGet('a'); //可以先天生一个函数
pGet(func); //须要时再传入回调函数实行
从上面的例子中可以发明,偏函数能使定义和实行星散,说来巧了,天生器可用于定义营业逻辑而天生器的next
用于推动营业实行,两者也是互相星散的。
天生器和偏函数
基于前面这么多铺垫,假定get
就是一个偏函数,以下:
function get(f) {
return function(callback) {
delay(100, function(s) {
callback(s + ':get ' + f);
});
};
}
这意味着,yield get('a')
使得next
函数实行的效果其value
属性值是个函数,该函数的参数是一个能吸收get
异步效果的回调函数,即:
g.next().value(function(value) {
g.next(value); //value成为yield的返回并继承推动营业逻辑
});
经由过程递归可以不停的实行天生器的next
要领,一个全新的经由过程天生器来完成营业逻辑的run
要领便呼之欲出了,
function run(gen) {
let g = gen();
function next(lastValue) {
let result = g.next(lastValue); //将上一个异步实行效果传出给当前的yield并实行下一个yield
if (result.done) {
return result.value;
}
//value是偏函数返回的新函数,它的参数是个用来吸收异步效果的回调函数
result.value(next); //next作为吸收异步效果的回调函数
}
next();
}
run(generator);
综合以上例子不难发明别的一个优点,经由过程偏函数可以使异步挪用api不受天生器的侵入,《ES6 异步编程之一:Generator》中完成的异步挪用须要将天生器作为参数,有兴致的话你可以尝试革新一下之前的示例。
如今经由过程新编写的run
函数便可以来实行本文一开始编写的谁人天生器了。
thunkify
偏函数的计划对api和天生器也是有侵入的,他请求:
api必需是偏函数情势;
天生器定义营业逻辑,每一个yield 背面的函数必需是挪用偏函数;
第二个题目是本计划的中心机制所请求,但第一个题目我们可以经由过程thunkify
来处理,api照旧根据get(value, callback)
体式格局定义,但定义天生器时须要将异步api挪用经由过程thunkify
转换为偏函数,以下:
let Thunkify = require('thunkify');
let thunkifiedGet = Thunkify(get);
function get(f, callback) {
delay(100, function(s) {
callback(s + ':get ' + f);
});
}
function* generator() {
let r1 = yield thunkifiedGet('a');
if (r1) {
let r2 = yield thunkifiedGet('b');
if (r2) {
console.log(yield thunkifiedGet('d'));
}
} else {
console.log(yield thunkifiedGet('c'));
}
}