Node.js 实战 4.Socket.IO 去掉传入参数影响

在现代的 Web 应用程序中,实时性已经逐渐成为一个基本要素。而其中最简单高效的解决方案之一,就是利用 Socket.IO

不过在实际开发过程中,很多人会遇到一个麻烦的问题,即:Socket.IO 的 emiton 方法,第一个参数通常是事件名称,而第二个参数则是待发送的数据。然而这种方法显然很不灵活,因为你无法直接控制是否发送第二个参数。而有时候,我们需要在事件名称的基础上再添加一些其他辅助信息,才能满足业务需求。

这篇文章就要告诉你,如何利用 JavaScript 的“偏函数”概念,解决这个问题,让你的 Socket.IO 应用变得更加灵活和健壮!

偏函数概述

所谓“偏函数”,顾名思义就是“部分应用一个函数”。也就是说,给定一个函数和部分参数,可以产生另外一个函数。

我们来看个例子。假设你有一个加法函数:

-------- ------ -- -
  ------ - - --
-

现在你需要一个函数,它总是加上 5。你可以这样做:

-------- ---------- -
  ------ ------ ---
-

可以看出,addFive 变成了 add 的“偏函数”。

如果换一个场景,假设你需要做一个高阶函数,把 add6 封装到一个函数里:

-------- --------------- -- -
  ------ ------- ---
-

这时候你就可以直接调用 otherFunc(add, 4),结果是 10。

了解了偏函数的概念,我们再来看看如何运用到 Socket.IO 上。

针对 Socket.IO 的问题

首先我们看一下 Socket.IO 常用的 emiton 方法,以及它们暴露的接口:

---------------------- ------
-------------------- ------ -- - --- ---

这里的 'message' 参数即为事件名称,data 则为需要发送的数据。然而,这样的设计并不太好,因为你无法将事件名称与其他参数“拼合”起来,只能在名称前面加一些固定的字符,比如 client-messageserver-message

如果你需要一些更复杂的业务逻辑,例如在前端 Angular 应用中使用 WebSocket,实现一个 “通过用户名发送信息” 的功能。会出现这样一种调用:

--------------------------------------- ---------

很遗憾,这么做显然是有问题的。考虑到 Socket.IO 允许一个事件可以有多个监听器,另一个使用 socket.on 监听该事件的地方也可能是这样调用的:

------------------------------------- --------- -- - --- ---

两边之间的信息不匹配,很有可能会造成难以预料的错误。

为什么会出现这个问题?是因为 Socket.IO 的固有设计限制吗?其实不是的。如果我们能够将“事件名称”与“其他参数”分离,把它作为一个对象传进去,就很容易解决这个问题了。

事实上,JavaScript 已经提供了相应的方法,bind。我们可以这样写:

------------------------ ----------- --------------------------- -------- ------------

在服务端的实现也类似:

------------------------- ------ -- -
  ----- -------- - --------------
  ----- ------- - -------------
  -- --- -- --------- ---
---

但是这样写并不优雅,需要大量重复代码,而且不容易维护。这边提供了一种更好的解决方法,即利用 JavaScript 的“偏函数”概念。

解决方法:深度应用偏函数

有了偏函数,我们可以有自动为 emiton 添加事件名称功能的函数,代码如下:

----- --------- - -------- ---------- -- -
  ------ ----- -- -
    ---------------------- -----
  --
--

----- ------- - -------- ---------- ----- -- -
  ------ -- -- -
    -------------------- ------
  --
--

如上所示,我们通过 curryEmitcurryOn 获得了一个“部分应用”的函数。即,在调用 curryEmit(socket, 'user-message') 时,会返回一个新的函数,这个新函数在调用时再传入 msg 参数。当我们需要发送 user-message 类型事件时,就可以直接调用此函数,像这样:

----- ----------- - ----------------- ----------------
-----------------

这在后续的代码编写中,非常方便。

同样,我们也可以使用 curryOn 实现将特定类型的事件附加到 socket.on 上的需求:

----- ----------------- - --------------- --------------- ----- -- -
  -- -- --------- ---- --- ---
---
--------------------

这样的好处是在之后的代码维护过程中,改变事件名称只需要改动一处,即 curryEmitcurryOn 调用的地方即可,其他代码不受影响。

当然,我们也可以使用一些高级技巧,将允许多个事件名称以及多个参数的情况下,使用“偏函数”的方式实现。如果你有了解拓展函数,可以参考如下代码实现:

-------- ------------------- --------- -
  -------- -------- -
    --- ----- - ---------
    ------ -------- ----------- -
      -- ------------ -- ------ -
        ------ ----------
      - ---- -
        ------ -------- --------------- -
          --- ------- - ----------------------
          ------ --------------
        -
      -
    -
  -
  --- ---- --------- -- --------- -
    --- - - ---------------------------
    -------------------- -----
  -
-

------------------- -
  --------------- ---------- -------- -- -
    -- -- --------- ---- -------- --- -------
  --
  ----------------- ---------- -------- ---- -- -
    -- -- --------- ---- --------- -------- --- ---
  -
---

实际案例—Angular + Socket.IO

以上理论处理了“事件名称”和“消息体”的问题之后,我们再来看一个实际的案例,也就是 Angular 客户端通过 Socket.IO 与服务器交互,发送和接受消息。

服务端代码非常基础,就不展开介绍了,读者可以直接到 GitHub 地址 查看。

下面是前端代码实现,首先我们需要引入 Socket.IO:

------ - -- -- ---- -------------------

接着连接 Socket.IO 服务器:

----------- ---- -
  -- ------- --- --- ------
  ----------- - ---------------------

  -- --------- -- -------- --------
  ------------------------------ ----- -- -
    --------------------- -------- ---------
  ---
-

在需要发送消息给服务端的地方调用:

---------------- -------- ---- -
  ----- ---- - ---------------------- ----------------
  ------------------- -------
-

代码中,curryEmit 函数接受一个 Socket.IO 的 socket 对象和一个事件名称,返回一个新的函数以便之后随时发送此事件。使用 curryEmit 函数我们生成了 send 函数,随时调用:

----- ---- - ---------------------- ----------------
------------------- -------

这时候就可以发送带参数的事件名称 user-message:{username} 给后端。

完整代码实现可以在 GitHub 上找到。

总结

在本文中,我们讲述了 Socket.IO 中常见的问题,以及这个问题带来的不便。随后我们介绍了偏函数的概念,并通过一些简单的示例说明了它的基本用法。最后,我们通过一个实际的案例,向读者展示了怎么样基于 Socket.IO 以及 Angular 实现一个更加灵活、健壮的“实时消息传递”应用。

“偏函数”之于 JavaScript,就像汽车之于路面,一样重要。它不仅提供了一种高效的设计思路,还能让我们的代码变得更加灵活、可读性和可维护性大大增强。

来源:JavaScript中文网 ,转载请联系管理员! 本文地址:https://www.javascriptcn.com/post/653dac487d4982a6eb768573


猜你喜欢

  • ES11 新特性之 Bigint 的应用与性能优化

    在最新版本的 ECMAScript (ES11) 中,引入了一项新的数据类型:BigInt。它可以用来表示更大范围的整数,解决了 JavaScript 中 Number 类型在处理超出其范围的整数时出...

    1 年前
  • Flexbox 入门教程:掌握这些变化布局无忧

    什么是 Flexbox? Flexbox 是一种 CSS 布局技术,用于在父元素和它的子元素之间进行灵活的对齐和分布。通过使用弹性盒子,您可以根据需要重新排列、拉伸或缩小页面上的元素,实现更加灵活的布...

    1 年前
  • Angular 中使用 ng-controller 指令的优缺点分析

    在 Angular 中,ng-controller 是一个重要的指令,它用来定义控制器,并将控制器和视图进行绑定。在编写 Anguler 应用程序时,我们经常使用 ng-controller 指令。

    1 年前
  • Express.js 中使用 Mongoose 进行 MongoDB 操作

    在前端开发中,MongoDB 是一个非常流行的 NoSQL 数据库,而 Express.js 则是一个常用的 Web 应用框架。Mongoose 则是一个优秀的 MongoDB 操作库,可以通过它非常...

    1 年前
  • 使用 Mocha 测试 Express 中间件

    Mocha 是一个功能强大的 JavaScript 测试框架,可以帮助我们编写和运行测试用例以确保代码在各种情况下都能正常工作。在本文中,我们将了解如何使用 Mocha 测试 Express 中间件,...

    1 年前
  • ES6 中的 Promise.all 和 Promise.race 解决异步编程问题

    在前端的开发中,异步编程是无法避免的。然而,异步编程有许多问题,如回调嵌套、回调地狱等,使得我们的代码变得难以维护和扩展。ES6 中提供了 Promise 对象来解决这个问题。

    1 年前
  • 在 ASP.NET Core Web 应用程序中使用 Server-Sent Events

    引言 Server-Sent Events (SSE) 是一种基于 HTTP 协议的协议,它可以实现服务器向客户端推送事件流的功能。在前端开发中,我们经常需要实时更新页面上的数据,例如在线聊天、股票行...

    1 年前
  • MongoDB 密码授权失败,如何排查?

    1、背景 MongoDB 是一种非常流行的 NoSQL 数据库,可以用于储存文档形式的数据,并且支持水平扩展,以及自动的数据分片。 在生产环境中,为了保护数据的安全性,我们通常会为 MongoDB 配...

    1 年前
  • 使用 GraphQL 技术加速 API 开发

    在传统的 API 开发中,我们通常会使用 RESTful API 来进行数据的传输和交互。但是随着业务的复杂性和需求的增多,使用 RESTful API 开发也出现了一些问题,比如需要多次请求才能获取...

    1 年前
  • TypeScript 中的命名函数:函数绑定的一种方式

    在 TypeScript 中,函数是一个重要的组成部分。而在函数的定义和使用中,使用命名函数是一个常见的方式。命名函数可以让你更好地组织你的代码,提高代码的可读性和可维护性。

    1 年前
  • 使用 Node.js 实现 SSH 连接的方法及注意事项

    #使用 Node.js 实现 SSH 连接的方法及注意事项 在前端开发中,访问远程服务器是一个常见的需求。其中,SSH 连接负责连接远程服务器,使得本地和远程可以进行数据交互和文件传输。

    1 年前
  • Cypress 测试中如何处理时间序列操作

    在前端开发过程中,我们经常需要对页面元素进行操作,并且需要考虑到用户交互和时间序列。Cypress 是一个开源的前端自动化测试框架,旨在帮助开发人员更轻松地进行前端测试。

    1 年前
  • 如何在 Deno 中使用 Express 实现 web 应用?

    前言 Deno 是一种安全、现代的运行时环境,与 Node.js 相比有许多的优点,比如原生支持 TypeScript、更安全等。而 Express 是一个常用的 Node.js 的 web 框架,也...

    1 年前
  • 如何在 RESTful API 中实现 OAuth2 认证

    OAuth2 是目前为止最流行的身份验证和授权协议之一。它使用了一个代理服务来代替客户端显示您的凭据,以便您可以授权第三方应用程序来访问您的资源。在本文中,我们将介绍如何在 RESTful API 中...

    1 年前
  • Fastify 应用中的消息队列使用指南

    随着现代网络应用的不断发展,消息队列成为了构建高可用、高并发系统的重要工具之一。而在 Node.js 领域,Fastify 是一款快速、低开销且高度可扩展的 Web 框架,拥有着优异的性能表现和完善的...

    1 年前
  • SASS 命名空间及其使用方法

    随着前端技术的不断更新和发展,CSS 预处理器已经成为了前端开发中不可或缺的一部分。其中 SCSS (Sassy CSS) 是一种 CSS 预处理器,它提供了更好的代码组织、模块化以及代码重用的机制。

    1 年前
  • SPA 应用中的代码分割和懒加载

    随着单页应用(SPA)的普及,前端工程的规模也逐渐变得庞大,代码质量问题也逐渐凸显。其中,SPA 应用中的代码分割和懒加载技术成为了必学技能。 什么是代码分割和懒加载 简单来说,代码分割就是将一个大的...

    1 年前
  • 在 Web Components 中使用 HTML 模板

    在 Web Components 中使用 HTML 模板 Web Components 是一个新兴的 WEB 技术,它的目标是通过扩展浏览器提供的 HTML、CSS、JavaScript,来实现可重用...

    1 年前
  • ES9 中的数组解构

    ES9 中增加了一些新特性,其中就包括数组解构。在编写前端代码时,我们常常需要从数组中提取数据并赋值给变量。ES9 中的数组解构可以让这个过程变得更加方便和简洁。 数组解构的基本语法 数组解构的语法是...

    1 年前
  • RxJS 调试技巧:利用 window 操作符分离数据流

    RxJS 作为前端开发中的重要工具之一,在数据流处理、异步编程等方面具有独特的优势。在实际应用中,我们常常需要对 RxJS 数据流进行调试,以便更好地理解和优化程序。

    1 年前

相关推荐

    暂无文章