generator(生成器)是ES6标准引入的新的数据类型。一个generator看上去像一个函数,但可以返回多次。
1、generator函数的定义是function*,这与普通函数是不同的
2、yield需使用在generator函数中,所表示的意思是“执行到这,并返回”
3、yield是有返回值的,其中value代表return的值,done代表函数是否执行结束。
yield 'your value'; // { value: 'your value', done: true }
yield; // { value: undefined, done: true }
generator跟函数很像,定义如下:
function* foo(x) { yield x + 1; yield x + 2; return x + 3; }
generator和函数不同的是,generator由function*
定义(注意多出的*
号),并且,除了return
语句,还可以用yield
返回多次。用处:可以编写一个产生斐波那契数列的函数:
function* fib(max) { var t, a = 0, b = 1, n = 0; while (n < max) { yield a; [a, b] = [b, a + b]; n ++; } return; }
fib(5)
直接调用一个generator和调用函数不一样,fib(5)
仅仅是创建了一个generator对象,还没有去执行它,它只是返回一个遍历器对象(Iterator Object)。
调用generator对象有两个方法,一是不断地调用generator对象的next()
方法:
var f = fib(5); f.next(); // {value: 0, done: false} f.next(); // {value: 1, done: false} f.next(); // {value: 1, done: false} f.next(); // {value: 2, done: false} f.next(); // {value: 3, done: false} f.next(); // {value: undefined, done: true} 如果继续调用next方法,返回的也都是这个值
next()
方法会执行generator的代码,然后,每次遇到yield x;
就返回一个对象{value: x, done: true/false}
,然后“暂停”。返回的value
就是yield
的返回值,done
表示这个generator是否已经执行结束了。如果done
为true
,则value
就是return
的返回值。当执行到done
为true
时,这个generator对象就已经全部执行完毕,不要再继续调用next()
了。
第二个方法是直接用for ... of
循环迭代generator对象,这种方式不需要我们自己判断done
:
for (var x of fib(10)) { console.log(x); // 依次输出0, 1, 1, 2, 3, ... }
yield 表达式如果用在另一个表达式中,必须放在圆括号里面:
{ function* demo() { console.log('Hello' + yield); // SyntaxError console.log('Hello' + yield 123); // SyntaxError console.log('Hello' + (yield)); // OK console.log('Hello' + (yield 123)); // OK } }
yield 表达式用作参数或放在赋值表达式的右边,可以不加括号:
{ function* demo() { foo(yield 'a', yield 'b'); // OK let input = yield; // OK } }
如果在 Generator 函数里面调用另一个 Generator 函数,默认情况下是没有效果的:
{ function* foo() { yield 'aaa' yield 'bbb' } function* bar() { foo() yield 'ccc' yield 'ddd' } let iterator = bar() for(let value of iterator) { console.log(value) } // ccc // ddd }
yield* 表达式用来在一个 Generator 函数里面 执行 另一个 Generator 函数:
{ function* foo() { yield 'aaa' yield 'bbb' } function* bar() { yield* foo() // 在bar函数中 **执行** foo函数 yield 'ccc' yield 'ddd' } let iterator = bar() for(let value of iterator) { console.log(value) } // aaa // bbb // ccc // ddd }
抽奖每抽一次提示一次剩余次数:
{ // 具体抽奖逻辑的方法 function draw(count) { // 执行一段抽奖逻辑 // ... console.log(`剩余${count}次`) } // 执行抽奖的方法 function* remain(count) { while(count > 0) { count-- yield draw(count) } } let startDrawing = remain(6) let btn = document.createElement('button') btn.id = 'start' btn.textContent = '开始抽奖' document.body.appendChild(btn) document.getElementById('start').addEventListener('click', function(){ startDrawing.next() }, false) }
generator 函数实现轮询:
{ // 请求的方法 function* ajax() { yield new Promise((resolve, reject) => { // 此处用一个定时器来模拟请求数据的耗时,并约定当返回的json中code为0表示有新数据更新 setTimeout(() => { resolve({code: 0}) }, 200) }) } // 长轮询的方法 function update() { let promise = ajax().next().value // 返回的对象的value属性是一个 Promise 实例对象 promise.then(res => { if(res.code != 0) { setTimeout(() => { console.log('2秒后继续查询.....') update() }, 2000) } else{ console.log(res) } }) } update() }
转载:https://www.liaoxuefeng.com/wiki/1022910821149312/1023024381818112