Javascript 这个来自YDKJS的委托递归示例到底是如何工作的?
我开始阅读《你不知道JS:Async和性能》一书,但在以下几点上绊倒了:我在心里仔细检查了代码,得到了正确的结果,但无法理解书中对中间步骤的描述 尝试将Javascript 这个来自YDKJS的委托递归示例到底是如何工作的?,javascript,promise,generator,Javascript,Promise,Generator,我开始阅读《你不知道JS:Async和性能》一书,但在以下几点上绊倒了:我在心里仔细检查了代码,得到了正确的结果,但无法理解书中对中间步骤的描述 尝试将console.log()插入函数体,尝试调试程序检查调用堆栈,但仍然无法将我的代码心智模型与书中的一致 function run(),它获取生成器函数作为参数,创建其实例并将其运行到底,将每个先前的yielded值传递给next()调用 function run(gen) { var args = [].slice.call( argu
console.log()
插入函数体,尝试调试程序检查调用堆栈,但仍然无法将我的代码心智模型与书中的一致
function run()
,它获取生成器函数作为参数,创建其实例并将其运行到底,将每个先前的yield
ed值传递给next()
调用
function run(gen) {
var args = [].slice.call( arguments, 1), it;
// initialize the generator in the current context
it = gen.apply( this, args );
// return a promise for the generator completing
return Promise.resolve()
.then( function handleNext(value){
// run to the next yielded value
var next = it.next( value );
return (function handleResult(next){
// generator has completed running?
if (next.done) {
return next.value;
}
// otherwise keep going
else {
return Promise.resolve( next.value )
.then(
// resume the async loop on
// success, sending the resolved
// value back into the generator
handleNext,
// if `value` is a rejected
// promise, propagate error back
// into the generator for its own
// error handling
function handleErr(err) {
return Promise.resolve(
it.throw( err )
)
.then( handleResult );
}
);
}
})(next);
} );
}
示例代码:
function *foo(val) {
if (val > 1) {
// generator recursion
val = yield *foo( val - 1 );
}
return yield request( "http://some.url/?v=" + val );
}
function *bar() {
var r1 = yield *foo( 3 );
console.log( r1 );
}
run( bar );
为了方便起见,我们可以像这样实现函数请求()
:
function request(url) {
return new Promise(function(resolve){
setTimeout(function(){
resolve( url.match(/v=(\d+)$/)[1] );
},1000);
});
}
本书提供了以下步骤:
run(bar)
启动*bar()
生成器foo(3)
为*foo(..)
创建迭代器,并将3
作为其val
参数传递3>1
,foo(2)
创建另一个迭代器,并将2
作为其val
参数传入2>1
,foo(1)
创建另一个迭代器,并将1
作为其val
参数传入1>1
为false
,因此我们下一次调用请求(..)
时使用1
值,并获得第一次Ajax调用的承诺yield*
将承诺传递回*foo(3)
生成器
例如。另一个yield*
将承诺传递给*bar()
生成器实例。再一次,另一个收益率*
通过了承诺
转到运行(…)
实用程序,它将等待该承诺(对于
第一个Ajax请求)继续*bar()
,它通过yield*
进入*foo(3)
实例,然后通过yield*
进入*foo(2)
生成器
实例,然后通过yield*
传递到正常的yield
它正在*foo(3)
生成器实例中等待*foo(3)
生成器实例,它将该值作为*foo(2
)实例中的yield*
表达式的结果发送回,以及
分配给其本地val
变量*foo(2)
内部,使用请求(…)
发出第二个Ajax请求,
其承诺是将返回到*foo(1)实例,然后
yield*
一直传播到run(..)
(第7步)。什么时候
承诺解决后,第二个Ajax响应将传播所有
返回到*foo(2)
生成器实例,并分配给
它的局部val
变量请求(..)
发出的,它的
promise进入运行(…),然后它的分辨率值出现
一路返回,然后返回
等待的在*bar()
中产生*
表达式yield*
进入正常yield
它正在*foo(3)
生成器实例中等待
为什么在foo(3)
中等待,而不是在foo(2)
中等待?我认为在履行承诺后,其值(1
)将传递给返回收益请求(“http://some.url/?v=“+val)代码>行,代替收益率
,因此我们在foo(1)
的末尾有返回1
。然后将1
传递给val=yield*foo(val-1)代码>行,再次代替yield
,因此我们在foo(2)
调用中有val=1
。在此之后,进行第二次request()
,并产生s对foo(3)
的承诺。
然后foo(3)
yield
s承诺bar()
,然后bar()
yield
s承诺run()
run()
等待第二个承诺,就像第一个承诺一样,依此类推
我忽略了什么
我忽略了什么
没什么。在步骤8和9中,他们应该引用的生成器是由foo(1)
创建的,而不是由foo(3)
创建的