2015-05-27 44 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);