es6+最佳入门实践(10)

10.Generator

10.1.Generator是什么?

Generator函数是ES6提供的一种异步编程解决方案。在它的内部封装了多个状态,因此,又可以理解为一种状态机,执行Generator函数后返回一个迭代器对象,使用这个迭代器对象可以遍历出Generator函数内部的状态

Generator函数和传统函数的不同点有:1 函数定义的时候,function关键字后面加“*”, 2 内部使用yield关键字定义内部状态


function* HelloGenerator() {
    yield "状态1";
    yield "状态2";
    yield "状态3";
    yield "状态4";
}

let hg = HelloGenerator();
console.log(hg.next());  //{value: "状态1", done: false}
console.log(hg.next());  //{value: "状态2", done: false}
console.log(hg.next());  //{value: "状态3", done: false}
console.log(hg.next());  //{value: "状态4", done: false}
console.log(hg.next());  //{value: undefined, done: true}

Generator函数被调用后,并不会立即执行完成,而是会在遇到yield关键字后暂停,返回的也不是函数的运行结果,而是一个执行内部状态的指针对象(Iterator对象)

注意1: next方法内可以传参数,这个参数的值作为上一次状态的返回值


function* HelloGenerator() {
    let result = yield "状态1";
    console.log(result);
    yield "状态2";
    yield "状态3";
    yield "状态4";
}

let hg = HelloGenerator();
console.log(hg.next());
console.log(hg.next('nodeing'));

注意2: 可以使用for...of来遍历Generator内部状态


function* HelloGenerator() {

    yield "状态1";
    yield "状态2";
    yield "状态3";
    yield "状态4";
}

let hg = HelloGenerator();

for( let i of hg){
    console.log(i);
}

注意3: 对象没有Symbol.Iterator属性,我们可以手动添加,让其具有Iterator接口

let obj = {};
function* gen() {
    yield 1;
    yield 2;
    yield 3;
    yield 4;
}
obj[Symbol.iterator] = gen;

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

10.2.Generator应用

1.限制抽奖次数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<button id="btn">抽奖</button>
<input type="text" id="ipt">
<script>
    let oBtn = document.getElementById('btn');
    let oIpt = document.getElementById('ipt');
    let start = gen(5);
    let timmer = null;
    oBtn.onclick = () => {
        start.next();
    };
    function draw(count) {
        clearInterval(timmer);
        let num = Math.floor(Math.random() * 30);
        let prize = 0;

        timmer = setInterval(()=>{
            prize++;
            if( num === prize){
                clearInterval(timmer);
                alert("还可以抽"+count+"次");
                return;
            }
            oIpt.value = prize;
        }, 100);

    }

    function* gen(count) {
        while (count > 0){
            count--;
            yield draw(count);
        }
    }
</script>
</body>
</html>

2.异步读取文件

const fs = require('fs');

function readFile(path) {
    return new Promise((resolve, reject) => {
        fs.readFile(path, (err, data) => {
            if(err){
                reject(err)
            }else {
                resolve(data)
            }
        })
    })
}

function* asyncFile() {
    yield readFile('a.txt');
    yield readFile('b.txt');
    yield readFile('c.txt');
}

let gen = asyncFile();
gen.next().value.then((data)=>{
    console.log(data.toString());
    return gen.next().value;
}).then((data2)=>{
    console.log(data2.toString());
    return gen.next().value;
}).then((data3)=>{
    console.log(data3.toString())

});

如果觉得上面的写法还比较麻烦的话,我们可以引入一个co模块,让aysncFile里面的代码自动执行

const co = require('co');

function* asyncFile() {
    let a = yield readFile('a.txt');
    let b = yield readFile('b.txt');
    let c = yield readFile('c.txt');
    console.log(a.toString(), b.toString(), c.toString())
}
co(asyncFile()).then(()=>{
    console.log('文件读取完成')
});

视频教程地址:http://edu.nodeing.com/course/50

原文地址:https://www.cnblogs.com/dadifeihong/p/10358130.html

时间: 2024-11-02 11:17:33

es6+最佳入门实践(10)的相关文章

es6+最佳入门实践(8)

8.Promise 8.1.什么是异步? 要理解异步,首先,从同步代码开始说 alert(1) alert(2) 像上面的代码,执行顺序是从上到下,先后弹出1和2,这种代码叫做同步代码 alert(0) setTimeout(function () { alert(1); }, 2000); setTimeout(function () { alert(2) }, 1000); alert(3) 上面代码的弹出顺序是 0 3 2 1 ,像这种不按从上到下依次执行的代码叫做异步代码,其实还有很多类

es6+最佳入门实践(1)

1.let和const 1.1.let和块级作用域 在es5中,js的作用域分为全局作用域和局部作用域,通常是用函数来区分的,函数内部属于局部作用域,在es6中新增了块级作用域的概念,使用{}括起来的区域是一个块级作用域 { var a = 10 } // 输出10 console.log(a) 如果上述代码中定义变量的时候使用let,在外面使用变量a就会报错 { let a = 10 } // 以下输出会报错 console.log(a) es6中新增了块级作用域,let定义的a只能在当前的{

es6+最佳入门实践(12)

12.class基础用法和继承 12.1.class基础语法 在es5中,面向对象我们通常写成这样 function Person(name,age) { this.name = name; this.age = age; } Person.prototype.showName = function () { console.log(this.name); }; let p = new Person("xiaoqiang", 10); p.showName(); 上面这种写法与传统的面

es6+最佳入门实践(7)

7.set和map数据结构 7.1.什么是set? Set就是集合,集合是由一组无序且唯一的项组成,在es6中新增了set这种数据结构,有点类似于数组,但是它的元素是唯一的,没有重复 let st = new Set([1,2,2,3,3,4]) console.log(st) // [1,2,3,4] Set的size属性可以知道set中有多少元素,类似于数组的length属性 let st = new Set([1,2,2,3,3,4]) console.log(st.size); //4

es6+最佳入门实践(6)

6.Symbol用法 6.1.什么是Symbol? Symbol是es6中一种新增加的数据类型,它表示独一无二的值.es5中我们把数据类型分为基本数据类型(字符串.数字.布尔.undefined.null)和引用数据类型(Object),在es6中新增的Symbol数据类型划分到基本数据类型 为什么会有这样一种数据类型呢? //别人给了你一个定义好的对象 var obj = { name: "xiaoqiang", showName: function(){alert(1)} } //

es6+最佳入门实践(9)

9.Iterator和for...of 9.1.Iterator是什么? Iterator又叫做迭代器,它是一种接口,为各种不同的数据结构提供统一的访问机制.这里说的接口可以形象的理解为USB接口,有了这个接口可以做不同的事情,在编程中所说的接口最终都是要通过一段代码块来实现这个接口功能的.而Iterator接口提供的统一访问机制主要表现为遍历操作,任何数据类型只要具有Iterator接口,就可以完成遍历操作(遍历操作指依次处理该数据结构的所有成员),总结起来就是说我们需要一种统一的机制来依次处

es6+最佳入门实践(2)

2.解构赋值 2.1.什么是解构赋值? 什么是解构赋值?这里的关键字还是赋值,这是说如何去赋值的问题,这里说的解构可以理解为解散重新构造,所以解构赋值可以理解为解散重新构造后进行赋值,通常是左边一种结构,右边一种结构,左右的结构拆开来一一对应进行赋值,例如: let a, b [a, b] = [1, 2] console.log(a, b) 这里就相当于把1赋值给a,把2赋值给b,这样的操作就叫做解构赋值,从本质上来说,结构解构赋值是一种匹配模式,只要等号两边的模式相同,那么左边的变量就可以被

es6+最佳入门实践(13)

13.模块化 13.1.什么是模块化 模块化是一种处理复杂系统分解为更好的可管理模块的方式.通俗的讲就是把一个复杂的功能拆分成多个小功能,并且以一种良好的机制管理起来,这样就可以认为是模块化.就像作家把书分成很多章节来写一样,程序员写代码分模块来写也是一种良好的习惯.从本质上来讲,一个模块就是一堆代码而已 使用模块化方式写代码,有非常多的优点,例如,可维护性好.避免全局变量污染.可复用性好等,下面我们来看看es5中如何实现模块化封装 var module1 = (function () { va

es6+最佳入门实践(5)

5.对象扩展 5.1.对象简写 在es5中,有这样一种写法 var name = "xiaoqiang"; var age = 12; var obj = { name : name, age : age } 在es6中,我们可以简写成这样一种形式 let name = "xiaoqiang"; let age = 12; let obj = { name, age } 以上只是属性的简写,如果有方法应该怎么写呢?首先我们来回顾一下es5中的写法 var obj =