网易首页 > 网易号 > 正文 申请入驻

Node.js中的异步Generator函数和Websockets

0
分享至

异步 generator 函数是 ES2018 中新增的特性。Node.js 从 v10 版本增加了对异步 generator 函数的支持。异步 generator 函数看似一个相当小众特性特性,但是却为 node.js websocket 框架提供了一个灵巧的使用机会。

在这篇文章中,我将说明 Node.js websocket 框架将如何使用异步 generator 函数。

HTTP 框架分类

首先,想一下 Express 或 Hapi 之类的 HTTP 服务器框架。一般来说,大多数 HTTP 服务器框架都属于以下三种之一:

1. 显式响应。 在 Express 中发送一个 HTTP 响应,你必须调用 res.end(),res.json() 或者 res 对象上的一些其他方法。换句话说,你必须显式调用一个方法来发送一个响应。

2. 使用 return 隐式响应。 另一方面,Hapi 在 v17 中明确地删除了 reply() 函数,也就是说 Hapi 没有等同于 res 的方式。如果需要发送一个响应。你只需在请求的处理方法中 return 一个返回值。之后 Hapi 就会将 return 的值封装进一个 HTTP 响应中。

3. 在适当的位置修改响应。 Koa 使用了一种混合了以上两种实现的独特处理方式。你将以修改 ctx 对象的方式,替代调用 res 对象的方法来构建响应。

换句话说,一些 HTTP 框架要求你显式调用方法来发送 HTTP 响应,另一些框架会提供给你一个可更改的 HTTP 响应对象,还有一些框架仅需要处理函数中 return 一个值。

Websockets 和 HTTP 的区别在于,Websockets 服务器可以在任何时间向 socket 推送消息,不管是不是基于某条消息的响应。也就是说,初级的 websocket 框架,例如 ws, 看起来很像 “显式响应” 模式:你需要显式调用一个方法用于发送一条消息。

然而,是否可以在保持允许消息多发这个优点的同时,使 websockets 可以实现隐式响应?这就是异步 generator 产生的原因。

从服务器上读取大块数据

假设你有一个一次读取一堆文档的 Mongoose 指针,并且你希望用 websocket 在每一个文档读出时尽快将它发送出去。这种方式有助于在任何时刻都使服务器的内存使用量保持在最小:客户端可以获取所有的数据,而服务器却不用为此在内存中一次保存所有的数据。举个例子,这是使用 async/await 方式读取一个指针的实现:

const User = mongoose.model('User', mongoose.Schema({ name: String }));
const cursor = Model.find().cursor();
for await (const doc of cursor) {
console.log(doc.name); // Print user names 1 by 1.

使 generator 函数变得有趣的地方在于,在一个函数中 yield 方法可以被调用多次,并且在上次停止的地方继续运行,除了这点以外,yield 方法和 return 方法类似。

const User = mongoose.model('User', mongoose.Schema({ name: String }));
async function* streamUsers() {
const cursor = Model.find().cursor();
for await (const doc of cursor) {
// Yielding each doc behaves like multiple implicit responses, if you have
// a framework that supports it.
yield doc;

以下是如何使用 Node.js 编写一个 Websocket 服务器:

const WebSocket = require('ws');
const server = new WebSocket.Server({
port: 8080
server.on('connection', function(socket) {
socket.on('message', function(msg) {
// Handle message

至此,接下来要做的是为 websocket 服务器添加 streamUsers() 方法。假设收到的每条消息都是有效的 JSON,并且都有属性 action 和 id。当 action === 'streamUsers'时,streamUsers() 就会被执行,并且基于 socket 向外发送每个被 Mongoose cursor 查询出来的用户。

const WebSocket = require('ws');
const server = new WebSocket.Server({
port: 8080
server.on('connection', function(socket) {
socket.on('message', function(msg) {
msg = JSON.parse(msg);
if (msg.action === 'streamUsers') {
void async function() {
// Send 1 message per user, as opposed to loading all users and then
// sending them all in 1 message.
for await (const doc of streamUsers()) {
socket.send(JSON.stringify({ id: msg.id, doc }));
}().catch(err => socket.send(JSON.stringify({ id: msg.id, error: err.message })));

以下是如何通过 websocket 客户端调用 streamUsers() 方法:

const client = new WebSocket('ws://localhost:8080');
// Will print each user doc 1 at a time.
client.on('message', msg => console.log(msg));
await new Promise(resolve => client.once('open', resolve));
client.send(JSON.stringify({ action: 'streamUsers', id: 1 }));
后续

异步 generator 函数提供了一种创建更高级的,如同一些 HTTP 框架(例如 Hapi 和 Fastify)那样,基于隐式响应的 websocket 框架的机会。而隐式响应的主要优势就在于,你在业务逻辑中不需要关注框架是通过 websocket,HTTP 轮询或是其他某种方式来发送结果。框架自由式 Javascript 编程更轻便并且更容易测试。

通过将所有产生的值存放在一个数组中,或者让客户端发起多次请求对一个指针进行迭代,streamUsers() 方法就可以很容易的在一个 HTTP 框架,或者是一个使用轮询的 HTTP 框架中重用。没有异步 generator 函数,所有这些都是不能实现的。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
收到阿萨德的求救信号,中方专机将赴中东,履行一年前给的承诺?

收到阿萨德的求救信号,中方专机将赴中东,履行一年前给的承诺?

贺文萍
2024-12-02 18:39:08
曝黄晓明叶珂已分手,分手原因疑曝光,叶珂伙同代购诈骗黄2000万

曝黄晓明叶珂已分手,分手原因疑曝光,叶珂伙同代购诈骗黄2000万

小盖纪实
2024-12-03 10:01:11
靳东的颜值进化史,简直拿了一部“逆袭”剧本 ​​

靳东的颜值进化史,简直拿了一部“逆袭”剧本 ​​

愚鉴
2024-12-03 15:47:22
国防部发声:不针对第三方

国防部发声:不针对第三方

新京报
2024-12-01 10:59:07
韩国总统戒严,竟然是为了他满脸玻尿酸的老婆和一个1.6万的包?

韩国总统戒严,竟然是为了他满脸玻尿酸的老婆和一个1.6万的包?

小果趣味体育
2024-12-04 16:39:34
曼城的窘境,或源于瓜帅的建队思路,但这也是瓜帅值得尊敬的地方

曼城的窘境,或源于瓜帅的建队思路,但这也是瓜帅值得尊敬的地方

足坛典故
2024-12-04 17:46:46
人民币兑美元汇率大幅上涨超300个基点|快讯

人民币兑美元汇率大幅上涨超300个基点|快讯

华夏时报
2024-12-04 16:19:06
它要清仓跑路?全铝豪车从30万降到14万多,全系2.0T+8AT,油耗8L

它要清仓跑路?全铝豪车从30万降到14万多,全系2.0T+8AT,油耗8L

小李车评李建红
2024-12-04 07:44:06
台当局忍了三天,决定开罚马英九基金会,并暗示将陆生团驱逐出境

台当局忍了三天,决定开罚马英九基金会,并暗示将陆生团驱逐出境

大光观察
2024-12-04 18:02:31
邻居不让地库里安装充电桩,怕自燃!比亚迪车主发公告:杞人忧天

邻居不让地库里安装充电桩,怕自燃!比亚迪车主发公告:杞人忧天

火山诗话
2024-12-04 05:17:20
创造营没成团,却嫁给200亿帅气总裁,27岁就已经成为人生赢家

创造营没成团,却嫁给200亿帅气总裁,27岁就已经成为人生赢家

小盖纪实
2024-12-03 16:11:25
结婚一月丈夫装瘫痪!趁妻子睡着,他用10厘米大钢钉敲入她脑袋

结婚一月丈夫装瘫痪!趁妻子睡着,他用10厘米大钢钉敲入她脑袋

历史看阿敞
2024-12-04 17:44:33
不留申花了?归化球员费南多近日搬家,他年底将是自由身

不留申花了?归化球员费南多近日搬家,他年底将是自由身

直播吧
2024-12-04 15:58:10
江苏宿迁,女子与拆迁队发生冲突致对方一死六伤,辩称是正当防卫

江苏宿迁,女子与拆迁队发生冲突致对方一死六伤,辩称是正当防卫

雪峰说法
2024-12-03 06:55:02
比亚迪要求供应商降价10%引争议!人民网:理所应当

比亚迪要求供应商降价10%引争议!人民网:理所应当

快科技
2024-12-03 15:53:49
台媒曝吴佩慈未婚夫被FBI通缉,涉案金额逾2330亿,她却不受影响

台媒曝吴佩慈未婚夫被FBI通缉,涉案金额逾2330亿,她却不受影响

开开森森
2024-12-04 08:05:18
贵州:震级4级或烈度5度及以上,将分级分类发布预警信息

贵州:震级4级或烈度5度及以上,将分级分类发布预警信息

暖心的小屋
2024-12-04 17:45:59
随着浙江狂胜吉林 山东逆转天津 新疆大胜宁波 CBA最新排名如下

随着浙江狂胜吉林 山东逆转天津 新疆大胜宁波 CBA最新排名如下

体坛热消息
2024-12-05 00:58:49
广州楼市全军覆没,广州天河区房价从4.7万涨至6.5万

广州楼市全军覆没,广州天河区房价从4.7万涨至6.5万

有事问彭叔
2024-12-04 17:35:06
特朗普乌克兰特使对普京的寡头顾问在新闻中开骂:你下地狱去吧

特朗普乌克兰特使对普京的寡头顾问在新闻中开骂:你下地狱去吧

探索星空
2024-12-04 20:57:55
2024-12-05 02:19:00

科技要闻

被字节起诉的实习生,写了AI顶会最佳论文

头条要闻

韩国执政党通过决定:反对弹劾尹锡悦

头条要闻

韩国执政党通过决定:反对弹劾尹锡悦

体育要闻

哈登,我不做大哥好多年

娱乐要闻

琼瑶在家中自杀离世,千字遗书曝光

财经要闻

牛市的悲歌

汽车要闻

表现够全能 柴油版二代哈弗H9或许更适合家用

态度原创

时尚
手机
数码
艺术
军事航空

今冬这三双鞋火了!洋气巨显腿长,谁穿谁好看!

手机要闻

红米K80 Pro更新澎湃OS2.0.11.0体验:不吐不快,说说真实感受

数码要闻

M5芯片iPad Pro将在2025年底投产 由比亚迪电子代工

艺术要闻

故宫珍藏的墨迹《十七帖》,比拓本更精良,这才是地道的魏晋写法

军事要闻

韩国国会对峙冲突现场:韩军破窗入楼

无障碍浏览 进入关怀版