我可以在 JavaScript Q 库中进行同步承诺吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17213297/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can I make a synchronous promise in the JavaScript Q library?
提问by PP.
I want to do something like the following:
我想做如下事情:
delay( 2500 )
.then( function () { console.log( "Step 1 done" ) } )
.then( delay( 7500 ) )
.then( function () { console.log( "Step 2 done" ) } );
So implementation of delay has been demonstrated many times before:
所以延迟的实现之前已经多次演示过:
function delay( ms ) {
var deferred = Q.defer();
setTimeout( deferred.resolve, ms );
return deferred.promise;
}
But if I run the above in node.js I get:
但是如果我在 node.js 中运行上面的代码,我会得到:
... delay of 2500ms
Step 1 done
Step 2 done
... delay of ~7500ms
rather than what I expect to see:
而不是我期望看到的:
... delay of 2500ms
Step 1 done
... delay of 7500ms
Step 2 done
In the examples provided on https://github.com/kriskowal/q/wiki/Examples-GalleryI can't find any examples of synchronous functions (functions that return a value without any callbacks involved) chained with promise functions.
在https://github.com/kriskowal/q/wiki/Examples-Gallery 上提供的示例中,我找不到任何与承诺函数链接的同步函数(返回值的函数,不涉及任何回调)的示例。
Any ideas how to mix in synchronous actions with asynchronous promises?
任何想法如何将同步操作与异步承诺混合?
I've tried:
我试过了:
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()} );
And this outputs:
这输出:
... delay of 2500ms
Time now is 2013-06-20
Time now is 2013-06-20
... delay of 7500ms
.. still not what I'm trying to achieve.
.. 仍然不是我想要达到的目标。
采纳答案by Felix Kling
If you want to chain the callbacks, you have to returna new promise object from one of the callbacks. In your first example, you write
如果要链接回调,则必须从其中一个回调中返回一个新的 Promise 对象。在你的第一个例子中,你写
.then( delay( 7500 ) )
which means you are passing a promise object to .then
, not a function. According to the Promise/A+ proposal(which Q follows), all non-function arguments must be ignored. So, basically it's the same as if you just write:
这意味着您将一个 promise 对象传递给.then
,而不是一个函数。根据Promise/A+ 提议(Q 跟随),必须忽略所有非函数参数。所以,基本上就像你写的一样:
delay( 2500 )
.then( function () { console.log( "Step 1 done" ) } )
.then( function () { console.log( "Step 2 done" ) } );
Instead, pass function which calls delay
and returns the promise object:
相反,传递调用delay
并返回承诺对象的函数:
delay( 2500 )
.then( function () { console.log( "Step 1 done" ); } )
.then( function () { return delay( 7500 ); } )
.then( function () { console.log( "Step 2 done" ); } );
Now the last callback will only be called once the promise object returned by delay
in the second callback is resolved.
现在,只有delay
在解决了第二个回调中返回的承诺对象后,才会调用最后一个回调。
回答by forforf
Google brought me here while working through a similar problem (but using Kris Kowal's Q), I ended up with a very small framework that lets you do the following:
Google 在解决类似问题时将我带到了这里(但使用了 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);
The framework is just 12 lines, and probably can be adapted for other promise libraries:
该框架只有 12 行,并且可能适用于其他 Promise 库:
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);
}
回答by Remo H. Jansen
If you work with Babel or TypeScript you could use the ES6 Generators:
如果您使用 Babel 或 TypeScript,您可以使用ES6 生成器:
'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);
});