ES6中Generator的应用

28 篇文章 2 订阅

Generator

介绍

Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同,Generator 函数有多种理解角度。语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。执行 Generator 函数会返回一个遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。

Generator函数有两个特征:

  1. function关键字与函数名之间有个星号;

  2. 函数内部使用yield表达式

function* helloWorldGenerator() { 
	yield 'hello'; 
	yield 'world'; 
	return 'ending'; 
}
//如上代码有三个状态, 'hello'、'world'、'ending'

执行

Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个迭代器对象,调用遍历器对象的next方法,使得指针移向下一个状态。也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。

let hw = helloWorldGenerator();
hw.next() // { value: 'hello', done: false }
hw.next() // { value: 'world', done: false }
hw.next() // { value: 'ending', done: true } 
hw.next() // { value: undefined, done: true }

应用

generator是实现状态机的最佳结构。

let flag = true;
function clock(){    
	if(flag){ console.log("tick");} else { console.log("tock"); }    
	flag = !flag;
}
function *  clock_generator(){    
  while(true){        
  console.log("tick"); yield;       
	console.log("tock"); yield;    
  }
}
clock();//tick滴
clock();//tock答
var cg=clock_generator();
cg.next();//tick {value:undefined,done:false}
cg.next();//tock {value:undefined,done:false}

案例:长轮询

// 定义一个generator函数,其返回值是一个promise
let ajax = function* () {
    yield new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve({
                code: 0
            })
        }, 1000);
    })
}


// 定义一个轮询函数,当轮询结果的code!=0时,1秒之后开始下一次轮询
let pull = function () {
    let generator = ajax();
    let step = generator.next();
    step.value.then((v) => {
        if (v.code != 0) {
            setTimeout(() => {
                console.log('wait');
                pull();
            }, 1000);
        } else {
            console.log(v);
        }
    })
}


pull(); // 执行

案例:抽奖

// 抽奖处理
let draw = function (count) {
    // 此处省略具体的抽奖逻辑
    console.log(`剩余${count}次`);
}


// 根据剩余次数判断是否执行抽奖处理
let residue = function* (count) {
    while (count > 0) {
        count--;
        yield draw(count);
    }
}


// 初始化抽奖次数为5次
let star = residue(5);


// 创建抽奖按钮
let btn = document.createElement('button');
btn.id = 'start';
btn.textContent = '抽奖';
document.body.appendChild(btn);


// 绑定抽奖事件
document.getElementById('start').addEventListener('click', () => {
    star.next();
}, false)

异步操作的同步化。可以把异步操作写在yield表达式里面,等到调用next方法时再往后执行。这实际上等同于不需要写回调函数了,因为异步操作的后续操作可以放在yield表达式下面,反正要等到调用next方法时再执行。所以,Generator 函数的一个重要实际意义就是用来处理异步操作,改写回调函数。

function* main() {  
	let result = yield request("http://some.url");  
    let resp = JSON.parse(result);    
	console.log(resp.value);
}
function request(url) {  
	// response参数会当做上一个yield表达式的返回值
	axios.get(url).then(function(response){it.next(response);});
}
it = main();
it.next();
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Generator函数</title>
  <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script>
    function* test(handle) {
      // 状态机通用函数
      handle();
      // 状态机通用变量
      let a = 1;
      // 状态机不通用res
      let res = yield getData();
      console.log(res);
      handle();
      console.log(a);
      yield "结束了";
    }
    let geo = test(function () {
      console.log(111);
    });
    geo.next();
    function getData() {
      // return 'hello'
      return $.get('http://47.106.244.1:8099/manager/category/findAllCategory', {}, (response) => {
        //发起状态机内第二段程序的执行
        geo.next(response);
      });
    }

  </script>
</head>
<body>
</body>
</html>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值