2013-06-20 14 views
15

Voglio fare qualcosa di simile al seguente:Posso fare una promessa sincrona nella libreria Q JavaScript?

delay(2500) 
    .then(function() { console.log("Step 1 done") }) 
    .then(delay(7500)) 
    .then(function() { console.log("Step 2 done") }); 

Così è stata dimostrata l'attuazione di ritardo molte volte prima:

function delay(ms) { 
    var deferred = Q.defer(); 
    setTimeout(deferred.resolve, ms); 
    return deferred.promise; 
} 

Ma se corro il suddetto in node.js ottengo:

... delay of 2500ms 
Step 1 done 
Step 2 done 
... delay of ~7500ms 

piuttosto che quello che mi aspetto di vedere:

... delay of 2500ms 
Step 1 done 
... delay of 7500ms 
Step 2 done 

Negli esempi forniti su https://github.com/kriskowal/q/wiki/Examples-Gallery non riesco a trovare alcun esempio di funzioni sincrone (funzioni che restituiscono un valore senza alcuna callback implicata) concatenato con funzioni promettenti.

Qualche idea su come mischiare azioni sincrone con promesse asincrone?

ho provato:

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

E questo uscite:

... delay of 2500ms 
Time now is 2013-06-20 
Time now is 2013-06-20 
... delay of 7500ms 

.. ancora non è quello che sto cercando di realizzare.

+1

Nel tuo primo esempio, hai provato '.then (function() {return delay (7500);})' invece di '.then (delay (7500))'? –

+0

@FelixKling che funziona per il primo e il secondo esempio! Fai quella tua risposta e io accetterò. –

+0

È ora possibile ottenere ciò senza dover specificare il tempo di ritardo per verificare la mia [risposta] (http://stackoverflow.com/questions/17213297/can-i-make-a-synchronous-promise-in-the-javascript-q -library/33298652 # risposta-33298652). –

risposta

13

Se si desidera concatenare i callback, è necessario restituire un nuovo oggetto promessa da uno dei callback. Nel tuo primo esempio, si scrive

.then(delay(7500)) 

che significa che si sta passando un oggetto promessa di .then, non una funzione. Secondo lo Promise/A+ proposal (che segue Q), tutti gli argomenti non funzionali devono essere ignorati. Quindi, in sostanza è la stessa come se basta scrivere:

delay(2500) 
    .then(function() { console.log("Step 1 done") }) 
    .then(function() { console.log("Step 2 done") }); 

Passare invece la funzione che chiama delay e restituisce l'oggetto promessa:

delay(2500) 
    .then(function() { console.log("Step 1 done"); }) 
    .then(function() { return delay(7500); }) 
    .then(function() { console.log("Step 2 done"); }); 

Ora l'ultima callback verrà chiamata solo una volta la promessa oggetto restituito da delay nel secondo callback è stato risolto.

3

Google mi ha portato qui mentre si lavora attraverso un problema simile (ma usando Q di Kris Kowal), ho finito con un piccolo quadro che consente di effettuare le seguenti operazioni:

var chain = [ 
    doNext(delay, 2500), 
    doNext(console.log, "Step 1 done"), 
    doNext(delay, 7500), 
    doNext(console.log, "Step 2 done") 
]; 

doInOrder(chain); 

Il quadro è a soli 12 linee , e probabilmente può essere adattato per altre biblioteche promessa:

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

Se si lavora con Babel o dattiloscritto è possibile utilizzare il 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); 
    }); 
Problemi correlati