2015-05-27 36 views
5

Potrzebuję uruchomić async generator (muszę mieć wynik w konsoli 1,2,3,4,5 bo teraz mam 4,1,2,3,5) ktoś może mi pomóc? Potrzebuję uruchomić zadanie i czekać, gdy poprzednie zadanie zostanie zakończone, zanim uruchomi następne zadanie. Muszę używać (jeśli to możliwe: tylko) generatory (? Lub generator + obietnica)Generator ES6 Javascript async

Oto mój kod

/*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

Spróbuj napisać rozwiązanie bez generatorów (z wykorzystaniem tylko zwrotnych lub obietnic) pierwszy. Wtedy moglibyśmy pokazać, jak włączyć generatory do tego obrazu - ponieważ same generatory nie są asynchroniczne. – Bergi

Odpowiedz

4

Można to zrobić wyłącznie za pomocą generatora. Oto przykład jednego podejścia, w którym przenosimy .next() do samego limitu czasu, aby zapewnić, że nie nastąpi on wcześniej. Dodatkowo generator teraz zwraca tę funkcję ze stosu zamiast go wykonywać, ponieważ nie można wywołać .next() na generatorze z poziomu samego generatora.

Warto tutaj zauważyć, że to nie jest sposób, w jaki robiłbym to "na wolności"; Obejmowałbym obietnice. Ale zapytałeś, czy można to zrobić tylko z generatorem - odpowiedź brzmi "tak".

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

Generatory na górze wywołań zwrotnych, a dokładniej :-) – Bergi

2

Istnieje wiele „zadanie prowadzenia” funkcje dla tego, można nawet napisać własny. Ale będziesz musiał użyć do tego Obietnic, a nie setTimeout. Oto krótki przykład:

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

Zasadniczo możemy wywołać metodę generatora next, czekać na to, aby zakończyć, a następnie ponownie odpalić metodę next i recurse aż generator zatrzymuje.

Bluebird ma bardziej odporną na błędy funkcję o nazwie Promise.coroutine.

Task.js: http://taskjs.org/ zapewnia specjalnie do tego funkcję.

Nadzieję, że pomaga!

1

Potrzebny jest sposób na twoje funkcje powiedzieć, kiedy będą gotowe. Obietnice są dobrym sposobem na rozwiązanie tego problemu.

będę trzymać się oryginalnego kodu tak dużo, jak tylko mogę:

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

Oczywiście, że wygląda brzydko i może ulec poprawie. Jak wspomniano w drugiej odpowiedzi, istnieją programy uruchamiające zadania i biblioteki kontroli przepływu, takie jak task.js, gen-run i co.

Z co, ostatnia część będzie:

co(generator1); 
Powiązane problemy