浅谈异步发展史(三):昙花一现的generator

前言

在我前面两篇文章中简单聊了聊异步的发展,从最开始的回调地狱,到后来的promise,再到手撕一个简单的promise。今天我们来聊聊generator构造器

正文

什么是generator

generator也是实现异步的一个方法,虽然它甚至不如直接使用promise来的快,可以说是十分的不好用。但是能够充分理解generator对学习async函数来说也是不可缺少的一环。

在前言中也提到了,generator是一个构造器函数,那么我们怎么去使用呢?或者说如何去实例化一个generator对象出来?答案很简单

js 复制代码
function* foo() {
    //function之后加一个星号就变成生成器函数
}

正如上面代码所示,只需要在function后面添加一个*就可以。而构造器函数能够默认返回一个generator对象,即使这个函数里面什么也没有

在generator对象中有一个十分重要的关键字------"yield"。这可以说是generator实现异步操作的关键,yield允许用户通过调用generator对象自带的next方法去手动控制代码的执行。例如:

js 复制代码
function* g() {
    let a = 1
    console.log(a);
    let b = yield a++
    console.log(b);
    let c = yield a++
    console.log(a);
}

let gen = g()

console.log(gen.next(), 'next1');//读取到1,再释放当前yield
console.log(gen.next(5), 'next2');
console.log(gen.next(), 'next3');

当generator内部存在yield去暂停函数代码的执行时,generator返回的对象则会有一些不同的变化

在这个对象中我们分别拿到了value和done。done好理解,代表generator内部是否执行完毕,那么value又是啥?根据上面的代码输出不难发现,value拿到的是紧跟在yield后面的值且默认值为undefined。也就是说每当我们调用一次next,就会得到一个新的generator对象,里面有两个键值对,分别代表yield后面的值,以及内部代码是否执行完毕。

为什么说是"昙花一现的generator"

首先要说明的是,所谓的昙花一现是指generator构造函数在异步处理方面是如此,而在其他地方并不一定也是昙花一现的。在很多人看来generator在异步处理这块最大的贡献就是为async和await这两块语法糖打下了坚实的基础。因为仅通过generator自身去实现异步的话,属实是有点反人类了。除此之外,Generator函数在推出之初,并没有得到广泛的社区支持和工具支持。相比之下,Promise和async/await很快就被各种框架和库所采纳,并且得到了广泛的推广和使用。不仅如此, Generator函数在某些情况下可能会导致性能问题,尤其是与async/await相比,后者在某些JavaScript引擎中可能有更好的性能优化。

最后,我个人认为没落的另一个原因在于不好理解,很容易造成混乱。在之前就提到过yield会拿到紧跟在后面的值,不仅如此,yield的值会被next传入的参数代替。

就以刚刚的代码为例子,按照正常思维来说,b的打印应该是a++完成之后的结果,但是当我们第二次调用next的时候传入了一个参数'5',所以导致了整个yield以及后面的代码的值被替换成了5。那我不传,就可以了吗?

js 复制代码
console.log(gen.next(), 'next2');

显然依旧是于事无补,因为next会默认返回一个undefined。

Await的前身---co

在co出现之前,要通过generator去实现异步还得搭配上promise,简直就是脱裤子放屁。就在generator快要消失的时候,出现了一个非常好用的co模块,无论是实现方式还是使用方式简直和后来出现的async/await一模一样,很难不怀疑js官方是不是直接抄了co模块。

Co的使用

首先,通过命令npm install co安装co模块

其次,在代码中引入co

js 复制代码
var co = require('co');

接着,将能够返回promise对象的函数放入generator构造器中。

js 复制代码
function a() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('a完成');
            resolve()
        }, 1000);
    })
}

function b() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('b完成');
            resolve()
        }, 500);
    })
}

function* c(f1, f2) {
    yield f1()
    yield f2()
}

最后,通过co处理异步

js 复制代码
co(c(a, b))

结果如下图:

总结

Generator函数作为JavaScript语言的重要特性,不仅极大提升了代码的可读性和可维护性,还为异步编程提供了新的思路和解决方案。通过灵活运用yield、yield*以及与Promise、async/await的结合,开发者可以更高效地管理复杂的数据流和异步逻辑,构建出更加健壮和优雅的应用程序。随着JavaScript生态的不断进化,掌握Generator的精髓对于每一位前端工程师来说都是不可或缺的技能。

相关推荐
XS030106几秒前
Java Web实现简易CRUD操作笔记
java·前端·笔记
Shadow(⊙o⊙)3 分钟前
qt内详解信号和槽的基本概念+实例演示
开发语言·前端·c++·qt·学习
qq_381338504 分钟前
Vue3 组合式函数设计模式:从基础封装到高级复用实战
前端·vue.js·设计模式
步十人4 分钟前
【CSS】基础一篇过
前端·css
回眸一笑吟离歌7 分钟前
edge浏览器更新后打开局域网服务报错:ERR_ADDRESS_UNREACHABLE
前端·edge
幽络源小助理10 分钟前
在线图片处理工具源码, 多功能编辑格式转换HTML单文件版
前端·html
humcomm13 分钟前
AI编程时代前端架构师的机遇和挑战
前端·架构·ai编程
折哥的程序人生 · 物流技术专研18 分钟前
《Java面试85题图解版(三)》上篇:高阶架构设计篇
java·开发语言·后端·面试·职场和发展
adminwolf22 分钟前
自研企业微信SCRM系统源码独立部署(Golang+Vue.js)
前端·vue.js·企业微信
小短腿的代码世界23 分钟前
QwtPolar 与实时示波器级渲染优化:雷达图到示波器曲线的极限性能调优
前端·qt·架构·交互