浅谈异步发展史(三):昙花一现的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的精髓对于每一位前端工程师来说都是不可或缺的技能。

相关推荐
Ranye12312 分钟前
从 JS 到 Dart:语法基础
javascript·flutter·dart
why技术39 分钟前
可以说是一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
后端·面试
烂蜻蜓43 分钟前
深入理解 Uniapp 中的 px 与 rpx
前端·css·vue.js·uni-app·html
Ama_tor1 小时前
网页制作06-html,css,javascript初认识のhtml如何建立超链接
javascript·css·html
木亦Sam1 小时前
响应式网页设计中媒体查询的进阶运用
前端·响应式设计
diemeng11191 小时前
2024系统编程语言风云变幻:Rust持续领跑,Zig与Ada异军突起
开发语言·前端·后端·rust
烂蜻蜓1 小时前
Uniapp 中布局魔法:display 属性
前端·javascript·css·vue.js·uni-app·html
视觉CG1 小时前
【Viewer.js】vue3封装图片查看器
开发语言·javascript·vue.js
java1234_小锋2 小时前
一周学会Flask3 Python Web开发-redirect重定向
前端·python·flask·flask3
白初&2 小时前
安全面试4
安全·面试·职场和发展