2013-06-20 36 views
15

我想要做的東西像下面這樣:我可以在JavaScript Q庫中做出同步承諾嗎?

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提供的示例中,找不到任何與promise函數鏈接的同步函數(返回一個沒有涉及任何回調的函數的函數)的示例。

任何想法如何混合異步承諾的同步行動?

我已經試過:

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 

..還沒有什麼,我想要的目的。

+1

在你的第一個例子中,你試過'.then(function(){return delay(7500);})''而不是'.then(delay(7500))'? –

+0

@FelixKling適用於第一個和第二個示例!作出你的回答,我會接受。 –

+0

你現在可以實現這一點,而不必指定延遲時間檢查我的[答案](http://stackoverflow.com/questions/17213297/can-i-make-a-synchronous-promise-in-the-javascript-q -library/33298652#答案-33298652)。 –

回答

13

如果你想連鎖回調,你必須返回一個新的承諾對象從其中一個回調。在你的第一個例子,你寫

.then(delay(7500)) 

這意味着你逝去的諾言對象.then,不是一個函數。根據Promise/A+ proposal(後面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返回的對象已解決。

3

谷歌把我帶到這裏,而通過一個類似的問題,工作(但使用克里斯·科瓦爾的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); 
} 
0

如果你有通天或打字稿工作,你可以使用ES6 Generators

'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); 
    });