mirror of
https://github.com/ruanyf/es6tutorial.git
synced 2025-05-24 10:22:23 +00:00
docs(generator): 使用 for...of 循环依次执行预定的操作步骤
This commit is contained in:
parent
8c06336a27
commit
3cbb8476e3
@ -348,46 +348,6 @@ for (let n of fibonacci()) {
|
||||
|
||||
从上面代码可见,使用`for...of`语句时不需要使用`next`方法。
|
||||
|
||||
由于`for...of`循环会自动依次执行`yield`命令,这启发我们可以将一些按步骤操作的任务,写在Generator函数里面。
|
||||
|
||||
```javascript
|
||||
let steps = [step1Func, step2Func, step3Func];
|
||||
|
||||
function *iterateSteps(steps){
|
||||
for (var i=0; i< steps.length; i++){
|
||||
var step = steps[i];
|
||||
yield step();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
上面代码中,数组`steps`封装了一个任务的多个步骤,Generator函数`iterateSteps`则是依次为这些步骤加上`yield`命令。
|
||||
|
||||
将任务分解成步骤之后,还可以将项目分解成多个依次执行的任务。
|
||||
|
||||
```javascript
|
||||
let jobs = [job1, job2, job3];
|
||||
|
||||
function *iterateJobs(jobs){
|
||||
for (var i=0; i< jobs.length; i++){
|
||||
var job = jobs[i];
|
||||
yield *iterateSteps(job.steps);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
上面代码中,数组`jobs`封装了一个项目的多个任务,Generator函数`iterateJobs`则是依次为这些任务加上`yield *`命令(`yield *`命令的介绍详见后文)。
|
||||
|
||||
最后,就可以用`for...of`循环一次性依次执行所有任务的所有步骤。
|
||||
|
||||
```javascript
|
||||
for (var step of iterateJobs(jobs)){
|
||||
console.log(step.id);
|
||||
}
|
||||
```
|
||||
|
||||
注意,上面的做法只能用于所有步骤都是同步操作的情况,不能有异步操作的步骤。如果想要依次执行异步的步骤,必须使用下一章介绍的方法。
|
||||
|
||||
利用`for...of`循环,可以写出遍历任意对象(object)的方法。原生的JavaScript对象没有遍历接口,无法使用`for...of`循环,通过Generator函数为它加上这个接口,就可以用了。
|
||||
|
||||
```javascript
|
||||
@ -1298,7 +1258,7 @@ step1(function (value1) {
|
||||
采用Promise改写上面的代码。
|
||||
|
||||
```javascript
|
||||
Q.fcall(step1)
|
||||
Promise.resolve(step1)
|
||||
.then(step2)
|
||||
.then(step3)
|
||||
.then(step4)
|
||||
@ -1313,12 +1273,12 @@ Q.fcall(step1)
|
||||
上面代码已经把回调函数,改成了直线执行的形式,但是加入了大量Promise的语法。Generator函数可以进一步改善代码运行流程。
|
||||
|
||||
```javascript
|
||||
function* longRunningTask() {
|
||||
function* longRunningTask(value1) {
|
||||
try {
|
||||
var value1 = yield step1();
|
||||
var value2 = yield step2(value1);
|
||||
var value3 = yield step3(value2);
|
||||
var value4 = yield step4(value3);
|
||||
var value2 = yield step1(value1);
|
||||
var value3 = yield step2(value2);
|
||||
var value4 = yield step3(value3);
|
||||
var value5 = yield step4(value4);
|
||||
// Do something with value4
|
||||
} catch (e) {
|
||||
// Handle any error from step1 through step4
|
||||
@ -1329,53 +1289,72 @@ function* longRunningTask() {
|
||||
然后,使用一个函数,按次序自动执行所有步骤。
|
||||
|
||||
```javascript
|
||||
scheduler(longRunningTask());
|
||||
scheduler(longRunningTask(initialValue));
|
||||
|
||||
function scheduler(task) {
|
||||
setTimeout(function() {
|
||||
var taskObj = task.next(task.value);
|
||||
// 如果Generator函数未结束,就继续调用
|
||||
if (!taskObj.done) {
|
||||
task.value = taskObj.value
|
||||
scheduler(task);
|
||||
}
|
||||
}, 0);
|
||||
var taskObj = task.next(task.value);
|
||||
// 如果Generator函数未结束,就继续调用
|
||||
if (!taskObj.done) {
|
||||
task.value = taskObj.value
|
||||
scheduler(task);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
注意,yield语句是同步运行,不是异步运行(否则就失去了取代回调函数的设计目的了)。实际操作中,一般让yield语句返回Promise对象。
|
||||
注意,上面这种做法,只适合同步操作,即所有的`task`都必须是同步的,不能有异步操作。因为这里的代码一得到返回值,就继续往下执行,没有判断异步操作何时完成。如果要控制异步的操作流程,详见下一节。
|
||||
|
||||
下面,利用`for...of`循环会自动依次执行`yield`命令的特性,提供一种更一般的控制流管理的方法。
|
||||
|
||||
```javascript
|
||||
var Q = require('q');
|
||||
let steps = [step1Func, step2Func, step3Func];
|
||||
|
||||
function delay(milliseconds) {
|
||||
var deferred = Q.defer();
|
||||
setTimeout(deferred.resolve, milliseconds);
|
||||
return deferred.promise;
|
||||
function *iterateSteps(steps){
|
||||
for (var i=0; i< steps.length; i++){
|
||||
var step = steps[i];
|
||||
yield step();
|
||||
}
|
||||
}
|
||||
|
||||
function* f(){
|
||||
yield delay(100);
|
||||
};
|
||||
```
|
||||
|
||||
上面代码使用Promise的函数库`Q`,`yield`语句返回的就是一个Promise对象。
|
||||
上面代码中,数组`steps`封装了一个任务的多个步骤,Generator函数`iterateSteps`则是依次为这些步骤加上`yield`命令。
|
||||
|
||||
如果`yield`语句后面的参数,是一个具有遍历器接口的对象,`yield`会遍历这个对象,再往下执行。这意味着,
|
||||
|
||||
多个任务按顺序一个接一个执行时,`yield`语句可以按顺序排列。多个任务需要并列执行时(比如只有A任务和B任务都执行完,才能执行C任务),可以采用数组的写法。
|
||||
将任务分解成步骤之后,还可以将项目分解成多个依次执行的任务。
|
||||
|
||||
```javascript
|
||||
function* parallelTasks() {
|
||||
let [resultA, resultB] = yield [
|
||||
taskA(),
|
||||
taskB()
|
||||
];
|
||||
console.log(resultA, resultB);
|
||||
let jobs = [job1, job2, job3];
|
||||
|
||||
function *iterateJobs(jobs){
|
||||
for (var i=0; i< jobs.length; i++){
|
||||
var job = jobs[i];
|
||||
yield *iterateSteps(job.steps);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
上面代码中,`yield`语句的参数是一个数组,成员就是两个任务taskA和taskB,只有等这两个任务都完成了,才会接着执行下面的语句。
|
||||
上面代码中,数组`jobs`封装了一个项目的多个任务,Generator函数`iterateJobs`则是依次为这些任务加上`yield *`命令(`yield *`命令的介绍详见后文)。
|
||||
|
||||
最后,就可以用`for...of`循环一次性依次执行所有任务的所有步骤。
|
||||
|
||||
```javascript
|
||||
for (var step of iterateJobs(jobs)){
|
||||
console.log(step.id);
|
||||
}
|
||||
```
|
||||
|
||||
再次提醒,上面的做法只能用于所有步骤都是同步操作的情况,不能有异步操作的步骤。如果想要依次执行异步的步骤,必须使用下一章介绍的方法。
|
||||
|
||||
`for...of`的本质是一个`while`循环,所以上面的代码实质上执行的是下面的逻辑。
|
||||
|
||||
```javascript
|
||||
var it = iterateJobs(jobs);
|
||||
var res = it.next();
|
||||
|
||||
while (!res.done){
|
||||
var result = res.value;
|
||||
// ...
|
||||
res = it.next();
|
||||
}
|
||||
```
|
||||
|
||||
### (3)部署iterator接口
|
||||
|
||||
|
@ -151,7 +151,7 @@
|
||||
- Mahdi Dibaiee, [ES7 Array and Generator comprehensions](http://dibaiee.ir/es7-array-generator-comprehensions/):ES7的Generator推导
|
||||
- Nicolas Bevacqua, [ES6 Generators in Depth](http://ponyfoo.com/articles/es6-generators-in-depth)
|
||||
- Axel Rauschmayer, [ES6 generators in depth](http://www.2ality.com/2015/03/es6-generators.html): Generator规格的详尽讲解
|
||||
- Derick Bailey, [Using ES6 Generators To Short-Circuit Hierarchical Data Iteration](https://derickbailey.com/2015/10/05/using-es6-generators-to-short-circuit-hierarchical-data-iteration/)
|
||||
- Derick Bailey, [Using ES6 Generators To Short-Circuit Hierarchical Data Iteration](https://derickbailey.com/2015/10/05/using-es6-generators-to-short-circuit-hierarchical-data-iteration/):使用 for...of 循环完成预定的操作步骤
|
||||
|
||||
## Promise对象
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user