2015-05-27 3 views
5

Мне нужно запустить генератор async (мне нужно получить результат в консоли 1,2,3,4,5, потому что теперь у меня есть 4,1,2,3,5), кто-нибудь может мне помочь? Мне нужно запустить задачу и дождаться завершения предыдущей задачи, прежде чем она запустит следующую задачу. Мне нужно использовать (если это возможно: только) генераторы (? Или генератор + обещание)Javascript ES6 генератор async

Вот мой код

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

Попытки написать решение без генераторов (с использованием только обратных вызовов или обещания) в первую очередь. Тогда мы могли бы показать вам, как включить генераторы в эту картину, потому что сами по себе генераторы не являются асинхронными. – Bergi

ответ

4

Это можно сделать исключительно с генератором. Вот пример одного подхода, в котором мы перемещаем .next() в самый тайм-аут, чтобы гарантировать, что он не произойдет раньше. Кроме того, генератор теперь возвращает функцию из стека вместо ее выполнения, потому что вы не можете вызвать .next() на генераторе из самого исполнения самого генератора.

Здесь стоит отметить, что это, вероятно, не так, как я сделал бы это «в дикой природе»; Я бы включил обещания. Но вы спросили, можно ли это сделать только с генератором - ответ «да».

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

генераторы поверх обратных вызовов, если быть точным :-) – Bergi

2

Есть много «задач работает» функции для этого, вы можете даже написать свой собственный. Но вам придется использовать Promises для этого, а не setTimeout. Вот краткий пример:

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

В принципе, мы называем next метод генератора, дождитесь его завершения, а затем снова огонь метод next и рекурсию, пока генератор не останавливается.

Bluebird имеет более отказоустойчивую функцию, называемую Promise.coroutine.

Task.js: http://taskjs.org/ обеспечивает функцию специально для этого.

Надеюсь, что это поможет!

1

Вам нужен способ для ваших функций, чтобы сказать, когда они закончили. Обещания - хороший способ решить эту проблему.

я буду придерживаться исходного кода столько, сколько я могу:

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

Конечно, это выглядит некрасиво, и может быть улучшена. Как упоминалось в другом ответе, есть бегуны задач и библиотеки управления потоком, такие как task.js, gen-run и co.

С co, последней частью будет:

co(generator1); 
Смежные вопросы