2015-05-27 12 views
5

Ho bisogno di eseguire il generatore asincrono (ho bisogno di avere risultato in console 1,2,3,4,5 perché ora ho 4,1,2,3,5) qualcuno mi può aiutare? Ho bisogno di eseguire attività e attendere quando l'attività precedente è terminata prima di eseguire l'attività successiva. Ho bisogno di utilizzare (se possibile: solo) Generatori (? O generatore + promessa)Javascript ES6 generatore asincrono

Ecco il mio codice

/*jshint esnext: true */ 
function show(msg) { 
    var _msg = msg; 
    setTimeout(function() { console.log(_msg);}, 2000); 
} 

function show2(msg) { 
    console.log(msg); 
} 

var stack = []; 

// add some function to stack 
stack.push(function() { show(1); }); 
stack.push(function() { show(2); }); 
stack.push(function() { show(3); }); 
stack.push(function() { show2(4); }); 
stack.push(function() { show(5); }); 

function* generator1() { 
    for(var key of stack) { 
    yield key(); 
    } 
} 
var gen = generator1(); 
gen.next(); 
gen.next(); 
gen.next(); 
gen.next(); 
gen.next(); 
+0

provare a scrivere una soluzione senza generatori (utilizzando solo callback o promesse) per primo. Quindi potremmo essere in grado di mostrarvi come incorporare i generatori in quella immagine, perché da soli i generatori non sono asincroni. – Bergi

risposta

4

Questo può essere fatto puramente con un generatore. Ecco un esempio di un approccio, in cui spostiamo lo .next() nel timeout stesso per assicurarci che non si verifichi presto. Inoltre, il generatore ora restituisce la funzione dallo stack invece di eseguirla, perché non è possibile chiamare .next() su un generatore dall'esecuzione del generatore stesso.

Vale la pena notare qui che questo probabilmente non è il modo in cui farei questo "in the wild"; Includerei le promesse. Ma tu hai chiesto se poteva essere fatto solo con un generatore - la risposta è "sì".

function show(msg) { 
    var _msg = msg; 
    setTimeout(function() { 
     console.log(_msg); 
     execute(); 
    }, 2000); 
} 

function show2(msg) { 
    console.log(msg); 
    execute(); 
} 

var stack = []; 

function execute() { 
    var fn = gen.next().value; 
    if (fn) fn(); 
} 

// add some function to stack 
stack.push(function() { show(1); }); 
stack.push(function() { show(2); }); 
stack.push(function() { show(3); }); 
stack.push(function() { show2(4); }); 
stack.push(function() { show(5); }); 

function* generator1() { 
    for(var key of stack) { 
    yield key; 
    } 
} 
var gen = generator1(); 
execute(); 

http://jsfiddle.net/smmccrohan/k271gz7o/

+0

generatori in cima a callback, per essere precisi :-) – Bergi

2

Ci sono molte funzioni "task in esecuzione" per questo, si può anche scrivere il proprio. Ma dovrai usare Promises per questo, e non setTimeout. Ecco un rapido esempio:

function delay (ms, val) { 
 
    return new Promise(function (res) { 
 
    setTimeout(res, ms || 1000, val || Math.random()); 
 
    }); 
 
    } 
 

 
function* run() { 
 
    yield delay(); 
 
    console.log(yield delay()); 
 
    yield delay(); 
 
    console.log('foo'); // sync calls anywhere in between 
 
    console.log(yield delay()); 
 
    } 
 

 
function async(gen){ "use strict"; 
 
    gen = gen(); 
 
    return Promise.resolve().then(function cont(a){ 
 
     var n = gen.next(a), 
 
      v = Promise.resolve(n.value); 
 
     if(n.done) return v; // a `return` 
 
     return n.value.catch(gen.throw.bind(gen)).then(cont); 
 
    }); 
 
}; 
 

 
async(run);

In sostanza, si chiama il metodo del generatore next, attendere che sia completato, e poi sparare di nuovo il metodo next, e recurse fino generatore arresta.

Bluebird ha una funzione più a prova di errore denominata Promise.coroutine.

Task.js: http://taskjs.org/ fornisce una funzione appositamente per questo.

Spero che questo aiuti!

1

è necessario un modo per le funzioni di dire quando sono finiti. Le promesse sono un buon modo per risolvere questo problema.

mi atterrò al codice originale come più possibile:

function show(msg) { 
    return new Promise(function(resolve){ 
    var _msg = msg; 
    setTimeout(function() { console.log(_msg); resolve(_msg);}, 2000); 
    }); 
} 

function show2(msg) { 
    return new Promise(function(resolve){ 
    console.log(msg); 
    resolve(msg); 
    }); 
} 

var stack = []; 

// add some function to stack 
stack.push(function() { return show(1); }); 
stack.push(function() { return show(2); }); 
stack.push(function() { return show(3); }); 
stack.push(function() { return show2(4); }); 
stack.push(function() { return show(5); }); 

function* generator1() { 
    for(var key of stack) { 
    yield key(); 
    } 
} 

var gen = generator1(); 
gen.next().value.then(function(){ 
    gen.next().value.then(function(){ 
    gen.next().value.then(function(){ 
     gen.next().value.then(function(){ 
      gen.next(); 
     }); 
    }); 
    }); 
}); 

Certo che sembra brutto, e può essere migliorato. Come accennato nell'altra risposta, esistono i task runner e le librerie di controllo del flusso, come ad esempio task.js, gen-run e co.

Con co, l'ultima parte sarebbe:

co(generator1); 
Problemi correlati