从iterator到generator

iterator

可遍历(可迭代)协定

一个对象为了变成可遍历对象,比如说能够用 for ... in 构造遍历其属性值,必需完成 @@iterator 要领, 意义是这个对象(或许它原型链 prototype chain 上的某个对象)必需有一个名字是 Symbol.iterator 的属性。

属性
[Symbol.iterator]返回一个对象的无参函数,被返回对象相符可遍历协定。

迭代器协定

当一个对象被认为是一个迭代器时,它完成了一个 next() 的要领。
该要领返回一个对象包括 donevalue 属性,done 的值示意迭代器是不是能够发生序列中的下一个值,value 为迭代器返回的任何 JavaScript 值。donetrue 时可省略。

let a = {
    q: 'q',
    w: 'w',
    e: 'e',
};
Object.defineProperty(a, length, {
    enumerable: false,
    value: 3
});

现在对 a 尝试用 for ... in 构造遍历其属性值

for (let v of a) {
    console.log(v);
}

报错:

Uncaught TypeError: a[Symbol.iterator] is not a function

定义一个函数应用闭包完成一个将 a 转变为可迭代对象

function Iterator(obj) {
    let i;

    return ()=> {
        return {
            next: ()=> {
                if (i < obj.length) {
                    for (i in obj) {
                        return {
                            done: false,
                            value: obj[i]
                        };
                    }
                }
                return {
                    done: true
                };
            }
        };
    };
}

a[Symbol.iterator] = Iterator(a);

generator

Generator 函数最大特性就是能够交出函数的实行权(即停息实行)。异步操纵须要停息的处所,都用 yield 语句说明。挪用 Generator 函数并不会实行本体,而是每次挪用 next 要领的时刻,实行到下一个遇到的 yield 处。

Generator 函数的数据交换

function* anotherGenerator(i) {
  yield i + 1;
  let x = yield i + 2;
  yield x + 3;
}

function* generator(i){
  yield i;
  yield* anotherGenerator(i);
  // 实行权转交给另一个 generator 函数的话 yield 后面带星号,直接挪用的话是没有效果的
  yield i + 10;
}

var gen = generator(10);

console.log(gen.next().value); // 10
console.log(gen.next().value); // 11
console.log(gen.next().value); // 12
console.log(gen.next(2).value); // 5
console.log(gen.next().value); // 20
// next 的返回值和迭代器的 next 相似,yield 语句的实行效果作为 value,是不是另有下一个 yield 决议 done
// next 要领能够带有参数,这个参数能够传入 Generator 函数,作为上个阶段异步使命的返回效果

Generator 函数的毛病处理

Generator 函数内部还能够布置毛病处理代码,捕捉函数体外抛出的毛病。

function* gen(x){
  try {
    var y = yield x + 2;
  } catch (e){ 
    console.log(e);
  }
  return y;
}

var g = gen(1);
g.next();
g.throw('出错了');
// 出错了

上面代码的末了一行,Generator 函数体外,运用指针对象的 throw 要领抛出的毛病,能够被函数体内的 try ... catch

Generator 函数的停止

Generator函数返回的遍历器对象,另有一个return要领,能够返回给定的值,而且闭幕遍历Generator函数。

function* gen() {
  yield 1;
  yield 2;
  yield 3;
}

var g = gen();

g.next()        // { value: 1, done: false }
g.return('foo') // { value: "foo", done: true }
g.next()        // { value: undefined, done: true }

假如Generator函数内部有try…finally代码块,那末return要领会推晚到finally代码块实行完再实行。

function* numbers () {
  yield 1;
  try {
    yield 2;
    yield 3;
  } finally {
    yield 4;
    yield 5;
  }
  yield 6;
}
var g = numbers()
g.next() // { done: false, value: 1 }
g.next() // { done: false, value: 2 }
g.return(7) // { done: false, value: 4 }
g.next() // { done: false, value: 5 }
g.next() // { done: true, value: 7 }

上面代码中,挪用return要领后,就最先实行finally代码块,然后比及finally代码块实行完,再实行return要领。

Generator 函数的自动实行

co 库是tj写的一个让Generator函数自动实行的东西。

let co = require('co');
let p = co(gen);

p.then(function (){
  console.log('ok');
})

co 函数返回一个 Promise 对象,因而能够用 then 要领添加回调函数。

async 与 await

ES7 为 generator 的语法糖

    原文作者:vanisseg
    原文地址: https://segmentfault.com/a/1190000005991887
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞