考虑:
// request(..)是一个支持Promise的Ajax工具
runAll(
function*(data){
data.res = [];
// 控制转移(以及消息传递)
var url1 = yield "http://some.url.2";
var p1 = request( url1 ); // "http://some.url.1"
// 控制转移 yield;
data.res.push( yield p1 );
},
function*(data){
// 控制转移(以及消息传递)
var url2 = yield "http://some.url.1";
var p2 = request( url2 ); // "http://some.url.2"
// 控制转移 yield;
data.res.push( yield p2 );
}
);
在这一方案中,实际上两个生成器不只是协调控制转移,还彼此通信,通过 data.res 和
yield 的消息来交换 url1 和 url2 的值。真是极其强大! 这样的实现也为被称作通信顺序进程(Communicating Sequential Processes,CSP)的更高
级异步技术提供了一个概念基础。对此,我们将在本部分的附录 B 中详细讨论。 4.7 形实转换程序
目前为止,我们已经假定从生成器 yield 出一个 Promise,并且让这个 Promise 通过一个像 run(…) 这样的辅助函数恢复这个生成器,这是通过生成器管理异步的最好方法。要知道, 事实的确如此。
但是,我们忽略了另一种广泛使用的模式。为了完整性,我们来简要介绍一下这种模式。
在通用计算机科学领域,有一个早期的前 JavaScript 概念,称为形实转换程序(thunk)。 我们这里将不再陷入历史考据的泥沼,而是直接给出形实转换程序的一个狭义表述: JavaScript 中的 thunk 是指一个用于调用另外一个函数的函数,没有任何参数。
换句话说,你用一个函数定义封装函数调用,包括需要的任何参数,来定义这个调用的执 行,那么这个封装函数就是一个形实转换程序。之后在执行这个 thunk 时,最终就是调用 了原始的函数。
举例来说:
function foo(x,y) {
return x + y;
}
function fooThunk() {
return foo( 3, 4 );
}
// 将来
console.log( fooThunk() ); // 7
所以,同步的 thunk 是非常简单的。但如果是异步的 thunk 呢?我们可以把这个狭窄的 thunk 定义扩展到包含让它接收一个回调。
考虑:
function foo(x,y,cb) {
setTimeout( function(){
cb( x + y );
}, 1000 );
}
function fooThunk(cb) {
foo( 3, 4, cb );
}
// 将来
fooThunk( function(sum){
console.log( sum );
} );
// 7
正如所见,fooThunk(…) 只需要一个参数 cb(…),因为它已经有预先指定的值 3 和 4(分 别作为 x 和 y)可以传给 foo(…)。thunk 就耐心地等待它完成工作所需的最后一部分:那 个回调。