2015-05-27 79 views
5

我需要運行生成器異步(我需要在控制檯1,2,3,4,5導致現在我有4,1,2,3,5結果)任何人都可以幫助我嗎?我需要運行任務,並在前一個任務完成之前等待它運行下一個任務。我需要使用(如果可能的話:只)發電機(?或發電機+承諾)Javascript ES6發生器異步

這裏我的代碼

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

有很多「任務運行」功能,您甚至可以自己編寫。但是你將不得不使用承諾這個,而不是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方法,以及遞歸直到發電機停止。

藍鳥有一個更具有防故障功能,稱爲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-runco

隨着co,最後一部分將是:

co(generator1);