我想做如下的事情:
delay( 2500 )
.then( function () { console.log( "Step 1 done" ) } )
.then( delay( 7500 ) )
.then( function () { console.log( "Step 2 done" ) } );
所以延迟的实现之前已经演示过很多次了:
function delay( ms ) {
var deferred = Q.defer();
setTimeout( deferred.resolve, ms );
return deferred.promise;
}
但是如果我在node.js中运行上面的代码,我得到:
... delay of 2500ms
Step 1 done
Step 2 done
... delay of ~7500ms
而不是我期望看到的:
... delay of 2500ms
Step 1 done
... delay of 7500ms
Step 2 done
在https://github.com/kriskowal/q/wiki/Examples-Gallery提供的示例中,我找不到任何同步函数(返回值而不涉及任何回调的函数)与承诺函数链接的示例。
任何想法如何在同步行动与异步承诺混合?
我试过:
function synchronousPromise() {
var deferred = Q.defer();
console.log( "Synchronous function call" );
deferred.resolve();
return deferred.promise;
}
delay( 2500 )
.then( function(){synchronousPromise()} )
.then( function(){delay( 7500 )} )
.then( function(){synchronousPromise()} );
输出:
... delay of 2500ms
Time now is 2013-06-20
Time now is 2013-06-20
... delay of 7500ms
. .还是不是我想达到的目标。
如果你想链接回调,你必须从其中一个回调中返回一个新的承诺对象。在第一个示例中,您写入
.then( delay( 7500 ) )
这意味着你正在传递一个promise对象给.then
,而不是一个函数。根据Promise/A+建议(Q遵循),必须忽略所有非函数参数。基本上和你写
delay( 2500 )
.then( function () { console.log( "Step 1 done" ) } )
.then( function () { console.log( "Step 2 done" ) } );
相反,传递调用delay
并返回承诺对象的函数:
delay( 2500 )
.then( function () { console.log( "Step 1 done" ); } )
.then( function () { return delay( 7500 ); } )
.then( function () { console.log( "Step 2 done" ); } );
现在,只有当delay
在第二个回调中返回的promise对象被解析后,才会调用最后一个回调。
当我在解决一个类似的问题(但使用Kris Kowal的Q)时,谷歌带我来这里,我最终得到了一个非常小的框架,可以让你做以下事情:
var chain = [
doNext(delay, 2500),
doNext(console.log, "Step 1 done"),
doNext(delay, 7500),
doNext(console.log, "Step 2 done")
];
doInOrder(chain);
框架只有12行,可能可以用于其他承诺库:
var Q = require('q');
function doNext(fn /* , arguments */){
var args = Array.prototype.splice.call(arguments, 1);
return function(prevRetVal){
// For my needs I didn't need the results from previous fns
return fn.apply(null, args)
}
}
function doInOrder(doNexters, init){
return doNexters.reduce(Q.when, init);
}
如果你使用Babel或TypeScript,你可以使用ES6 generator:
'use strict';
let asyncTask = () =>
new Promise(resolve => {
let delay = Math.floor(Math.random() * 1000);
setTimeout(function () {
resolve(delay);
}, delay);
});
let makeMeLookSync = fn => {
let iterator = fn();
let loop = result => {
!result.done && result.value.then(res =>
loop(iterator.next(res)));
};
loop(iterator.next());
};
makeMeLookSync(function* () {
let result = yield asyncTask();
console.log(result);
});