js核心之Generator函数

先有问题再有答案

  1. js中函数有几种运行状态
  2. Generator是什么
  3. Generator有什么特性
  4. Generator有哪些应用场景
  5. babel在低版本是如何处理Generator的

函数运行的三种状态

进程&线程&协程

进程是计算机分配资源的最小单位
线程是操作系统执行的最小单位
协程是程序可以在任何地方暂停,然后在稍后的某个时间点从暂停的地方恢复执行。Generator函数是协程在 ES6 的实现

协程&线程的区别:

  1. 并发性 :线程是操作系统级别的并发单位,可以同时运行在多个处理器上,实现真正的并行执行。而协程是程序级别的,它们在同一时间只能有一个在运行,实现的是并发而非并行
  2. 切换开销:线程的切换需要涉及到操作系统的介入,保存和恢复线程上下文,开销相对较大。而协程的切换只需要在程序级别保存和恢复上下文,开销较小。
  3. 控制方式:线程的调度由操作系统负责,程序员无法直接控制。而协程的调度由程序员在代码中显式控制,可以精确地控制何时挂起和恢复协程。
  4. 数据安全:由于线程可以并行执行,因此需要使用锁等机制来防止数据竞争。而协程由于在同一时间只有一个在运行,因此不存在数据竞争的问题。

在 JavaScript 中,由于其单线程的特性,协程(通常通过Generator或 async/await 实现)被广泛用于处理异步操作,使得异步代码可以以类似同步的方式编写和理解。

Generator特性

可交出执行权,可暂停可恢复

javascript 复制代码
function* test() {
    console.log('1111');
    yield;
    console.log('3333');
}

const g = test();
g.next();
console.log('2222')
// 打印 1111  2222

再次调用g.next() 从yield处恢复执行
// 打印 3333

可在函数运行时动态注入数据

javascript 复制代码
function* test() {
    console.log('1111');
    const p = yield;
    console.log('2222')
    if(p === '3333'){
      console.log('p', p);   
    }   
}

const g = test();
g.next();
g.next('3333'); // 这里输入的参数 改变了函数运行结果

在函数执行到一半 动态传入一些参数 改变函数的执行结果 这是js中其他函数不具备的能力

可优化性能 按需执行.

假如有一组字符串例如1243-123-234-6-456....形式,需要我们找出是否包含666666的数字,这个输入的字符串又很大,我们直接将字符串转换为数组会很占用内存,这个时候也可以使用generator函数。

ini 复制代码
function* find(str){
  let c = '';
  let i = 0;
  while(true){
    if(!str[i]){
      yield c;
      return; 
    }
     if(str[i]=== '-'){
         yield c; 
         c = '';
         i++;
         continue;
     }
      
      c += str[i];
      i++;
      
  }
}
const gen = find('1243-123-234-6-456')
console.log(gen.next().value) // 1243
console.log(gen.next().value) // 123
console.log(gen.next().value) // 234 ...

Generator应用场景

异步场景

Generator是协程在es6的实现 可以说天然就是为了异步而生的。不过由于Generator&yield使用起来不方便,返回的是一个迭代器需要手动运行解析 因此有了async&await做进一步的封装。

实现迭代器Iterator

ini 复制代码
let obj = {
  name: 'test',
};
[...obj] //  Uncaught TypeError: obj is not iterable


let obj = {
  name: 'test',
  [Symbol.iterator]: function* () {
      yield 1;
      yield 2;
      yield 3;
  }
};
[...obj] // [1, 2, 3]

对象不支持迭代 这里通过与symbol配合实现了迭代的能力。

状态机

生成器函数可以用来实现状态机。状态机是一种抽象的计算模型,它可以处于一系列的状态中的一个,且在任一时刻,只能处于这些状态中的一个。生成器函数使用 yield 关键字来暂停函数的执行,然后使用生成器的 next 方法来恢复执行,这正好满足了状态机的特性。

scss 复制代码
function* trafficLight() {
    while (true) {
        yield { color: 'green', duration: 5000 };
        yield { color: 'yellow', duration: 3000 };
        yield { color: 'red', duration: 2000 };
    }
}

const light = trafficLight();

function changeLight() {
    const state = light.next().value;
    console.log(state.color);
    setTimeout(changeLight, state.duration);
}

changeLight();

使用Generator实现一个交通信号灯的状态机。

babel&Generator源码

facebook的源码 regenerator

一个例子:

lua 复制代码
function* foo() {
  yield 'result1'
  yield 'result2'
  yield 'result3'
}
  
const gen = foo()
console.log(gen.next().value)
console.log(gen.next().value)
console.log(gen.next().value)

babeljs编译后的代码

generator代码解析可以看下这个文章

参考

es6_generator

相关推荐
2分钟速写快排27 分钟前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60611 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角2 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!2 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰3 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
Interview Aid1123 小时前
Walmart Global Tech SDE 三轮面经|基础、并发、压力面
面试·职场和发展
mayaairi4 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen5 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马5 小时前
AI源码分析:拆解模型底层实现逻辑
前端
BillKu5 小时前
全局样式变量:CSS 自定义属性(--border-color)和SCSS 变量($border-color)的说明
javascript·css·scss