2013-06-20 3 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 Я не могу найти примеры синхронных функций (функций, возвращающих значение без каких-либо обратных вызовов), прикованных с функциями обещания.

Любые идеи, как смешивать синхронные действия с асинхронными обещаниями?

Я пробовал:

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

Google привел меня сюда во время работы через подобную проблему (но с использованием Q Kris Коваля в), я закончил с очень небольшой структурой, которая позволяет выполнить следующие действия:

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