jsynchronous

jsynchronous

高效实时同步JavaScript应用状态库

jsynchronous是一个JavaScript库,用于实时同步快速变化的应用状态。它确保客户端浏览器与服务器保持数据一致性。该库速度适用于游戏开发,灵活性可用于图形应用。jsynchronous提供简单API,允许在Node.js服务器上注册JavaScript数组或对象,并在浏览器上自动同步。支持服务器间同步,并具有实验性的浏览器到服务器同步功能。

Jsynchronous.js同步实时通信WebSocketJavaScriptGithub开源项目

Jsynchronous.js

将您快速变化的应用状态与所有连接的浏览器同步。

Jsynchronous 确保所有客户端看到的数据与服务器上的数据相同 - 即使数据正在变化。速度快到足以用于游戏,灵活到可以用于图形应用,并经过精确测试。

在 Node.js 服务器上使用 jsynchronous 注册一个普通的 JavaScript 数组或对象,连接的浏览器上就会有一个完全相同的副本:

// 服务器端 const physics = {velocity: {x: 5, y: 1.01}}; const $ynchronized = jsynchronous(physics);
// 浏览器端 console.log(jsynchronous()); { velocity: {x: 5, y: 1.01} }

对该变量的更改将自动传达给浏览器,以便它们始终保持同步:

// 服务器端 $ynchronized.velocity.x += 5; $ynchronized.velocity.y -= 9.81;
// 浏览器端 console.log(jsynchronous()); { velocity: {x: 10, y: -8.8} }

以下是您可以用 jsynchronous 同步的各种数据类型:

const data = { string: '$†®îñG', integer: 123467890, floating: 3.141592653589793, bigint: BigInt('12345678901234567890'), null: null, undefined: undefined, bool: true, array: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233], deep: {a: {very: {deeply: {nested: {data: ['structure']}}}}}, circular: {a: {b: {c: null}}} } data.circular.a.b.c = data.circular; const $ynced = jsynchronous(data);

Jsynchronous 还可以处理服务器之间的同步,或(实验性地)浏览器到服务器的同步。

设置

按照示例代码片段进行轻松集成。

Jsynchronous 不会将您限制在特定的传输媒介上,无论是 socket.iowsPrimusEventSource 还是 webRTC。任何具有最终有序交付的协议都可以使用。在这个例子中,我们将使用 ws

服务器端设置包含 3 个必需步骤:

  1. 指定 jsynchronous.send 函数
  2. 通过调用 jsynchronous() 创建同步变量
  3. 使用 .$ync(websocket) 将连接的 WebSocket 注册到您的同步变量
// 服务器端使用 ws 库 const jsynchronous = require('jsynchronous'); const WebSocket = require('ws'); jsynchronous.send = (websocket, data) => websocket.send(data); const $matrix = jsynchronous([[1, 2], [3, 4]]); const wss = new WebSocket.Server({port: 8080}); wss.on('connection', (websocket) => { $matrix.$ync(websocket); websocket.on('close', () => $matrix.$unsync(websocket)); });

jsynchronous.send = (websocket, data) => {} 函数在每次需要向客户端发送数据时都会被 jsynchronous 自动调用。它必须包含将数据传输到 WebSocket 客户端的代码。

调用 jsynchrounous() 会创建并返回一个同步变量。在这个例子中是 $matrix。调用 $matrix.$ync(websocket) 将使该同步变量对该 WebSocket 可见。

我们在同步变量名中使用 $ 是因为这是一种约定。您不必这样做,但在代码中有一些指示,表明对服务器上这个变量的更改会导致网络通信,这是很好的做法。

现在数据正在从服务器发送,让我们关注客户端。在浏览器中,可以通过以下两种方式之一访问 jsynchronous 客户端:

<script src="/jsynchronous-client.js"></script>
import jsynchronous from 'jsynchronous/jsynchronous-client.js';

第一种方法需要作为静态资源提供,或者从 CDN 提供。第二种方法需要使用像 webpack 这样的打包工具。

// 浏览器端 const ws = new WebSocket('ws://localhost:8080'); ws.onmessage = (data) => jsynchronous.onmessage(data.data);

就这么简单!在客户端查看同步变量的内容:

// 浏览器端 console.log(jsynchronous());

查看示例设置中的示例代码以获取指导。

还有一个可选步骤是启用浏览器到服务器的通信,这有助于从网络中断中恢复,我们将在下面讨论。

替代变量

在服务器上调用一次 jsynchronous() 而不提供名称将创建一个主变量。客户端可以通过在建立通信后调用一次 jsynchronous() 来查看主同步变量。

**在客户端上变量尚未同步时调用 jsynchronous() 将导致错误!**为了避免这种情况,请在第一个参数中指定预期的类型 'array' 或 'object':

// 浏览器端 const $matrix = jsynchronous('array');

如果客户端尚未完成同步,$matrix 将返回一个提供的类型的替代变量。替代变量最初只是空数组或对象。当客户端同步并更新后,替代变量将相应更新。

替代变量的替代方案是等待调用 jsynchronous()。您可以随时使用 jsynchronous.list() 查看哪些同步变量可用。

多个同步变量

在服务器上多次调用 jsynchronous() 将创建额外的同步变量,但您必须通过传入名称作为第二个参数来命名它们:

// 服务器端 const $greetings = jsynchronous({text: 'hello world'}, 'greetings');

在客户端上,通过在第二个参数中引用其名称来检索它:

// 客户端 const $greetings = jsynchronous('object', 'greetings');

您可以使用 jsynchronous.list() 查看名称列表。

连接中断和重新同步

TCP/IP 连接重置的原因有很多。失去服务、关闭笔记本电脑或计算机进入睡眠状态、用手机进入地下或电梯、在以太网、Wi-Fi 或蜂窝数据之间切换。有时路由器或网络本身会出现故障。许多 WebSocket 库会在 TCP/IP 中断后恢复会话,但不保证在 TCP/IP 连接断开时发送的消息能够送达。

无论用户断开连接多长时间,Jsynchronous 都会确保用户重新连接时进行重新同步。它通过对所有消息进行编号并重新请求缺失的范围来实现这一点 - 这通常是 TCP/IP 处理的... 当它没有中断时。

为了支持重新同步请求,需要客户端到服务器的通信。您需要在客户端添加 jsynchronous.send,并在服务器上调用 jsynchronous.onmessage(websocket, data) 来接收发送的数据。类似于之前的设置,但在客户端和服务器上都有 .send 和 .onmessage。还要注意服务器端函数需要传入 websocket。

// 服务器端 jsynchronous.send = (websocket, data) => websocket.send(data); const $ynchronized = jsynchronous(['Quoth', 'the', 'raven', '"Nevermore."']); const wss = new WebSocket.Server({port: 8080}); wss.on('connection', (websocket) => { $ynchronized.$ync(websocket); websocket.on('message', (data) => jsynchronous.onmessage(websocket, data)); websocket.on('close', () => $ynchronized.$unsync(websocket)); });
// 浏览器端 const ws = new WebSocket('ws://localhost:8080'); ws.onmessage = (data) => jsynchronous.onmessage(data.data); jsynchronous.send = (data) => ws.send(data);

const $ynchronized = jsynchronous('object');


设置客户端到服务器的通信可以使您的同步变量能够抵抗数据丢失和不同步。默认情况下,如果您没有在客户端提供.send或在服务器上提供.onmessage,客户端将给出警告,如果消息丢失且无法重新同步,则会停止。

并非所有应用程序都需要这种级别的保护,可以依赖TCP/IP提供的保证。通过在服务器上调用jsynchronous()时将{one_way: true}作为选项来完全禁用客户端到服务器的通信。如果您保持同步变量的初始结构不变,只更改原始值(字符串、数字、布尔值),而不给对象或数组分配任何新引用,单向模式效果很好。丢失的消息将被忽略,jsynchronous将尽最大努力继续更新已同步对象/数组的属性。

# 回溯模式

回溯模式是jsynchronous的一个强大功能。回溯模式允许您"回溯"到数据的先前快照。

想象一场国际象棋比赛。在普通模式下,不可能回退几步来查看过去棋盘的样子。使用回溯模式,您可以看到游戏中任何一步棋盘的样子。使用回溯模式,暂停、回溯和向前播放更改都成为可能。

通常,客户端一旦更新就会丢弃更改历史以节省内存。使用回溯模式,客户端从一开始就获得完整的历史记录。可以将历史应用于初始状态,以重建历史中的任何时刻。这被称为事件溯源。

通过在服务器上调用同步变量的.$napshot()来创建快照:

```javascript
// 服务器端
const $ynced = jsynchronous([], 'name', {rewind: true});

$ynced.push(Math.random());
$ynced.$napshot('one');

$ynced.push(Math.random());
$ynced.$napshot('two');

您可以通过调用.$rewind(name)回溯到快照

const previous = $ynced.$rewind('one');

如果您的客户端期望按照更改发生的顺序接收更改,而不考虑客户端何时连接到活跃变化的状态,回溯模式也可能很有用。

对于大型历史记录,重建当前状态可能在网络和计算上都很密集,因此请注意不要对启用回溯模式的变量应用无限数量的更改。

安全和权限

Jsynchronous中的权限设置很简单。如果您不希望某个websocket看到同步变量中包含的数据,就不要调用.$ync(websocket)。

建议为应用程序中不同级别的权限和可见性创建额外的同步变量。

事件

通过在同步变量上使用.$on('changes', callback)来观察、监听、触发更改事件:

$ynchronized.$on('changes', () => {})

目前这只在客户端可用。未来的版本将会看到更多类型的事件和更多跟踪更改的方式。敬请期待!

故障排除

最常见的错误是对传入jsynchronous()的数据进行赋值,而不是对jsynchronous()返回的同步变量进行赋值,这会让您疑惑为什么数据没有被传输。

// 服务器端 const physics = {x: 0, y: 0, z: 0} const $ynced = jsynchronous(physics); physics.x += 10; // 不会同步!

要在客户端看到更改,上述代码必须修改$ynced,而不是physics。Jsynchronous会创建您传入的变量的深度副本,完全忽略原始数据。在将对象或数组分配给同步变量时也是如此:

const quaternion = {w: 1, i: 0, j: 0, k: 0} $ynced.orientation = quaternion; // 会同步 $ynced.orientation.w = 0; // 会同步 quaternion.i = 1; // 不会同步

在将对象和数组分配给同步变量时要小心。所有内容都将对.$ync()中的客户端可见。

另一方面,您可以从应用程序的其他部分引用同步变量。对这些引用的更改将会同步:

const $orientation = $ynced.orientation; $orientation.i = 0; // 会同步 $orientation.j = 1; // 会同步

我们建议您在引用同步变量时使用前缀'$'或其他约定,以表明该变量是响应式的,对该变量的赋值将通过网络发送。

文档参考

Jsynchronous()函数调用

jsynchronous(data, name, options);

创建并返回一个同步变量。

在服务器上,data必须是一个对象或数组。 在客户端,data必须是匹配'array'或'object'的字符串。

Jsynchronous方法

send

// 服务器端 jsynchronous.send = (websocket, data) => {} // 客户端 jsynchronous.send = (data) => {}

默认未定义,您必须将其分配给一个传输数据的函数。Websocket将匹配您在调用同步变量的$ync(websocket)方法时提供的值。

onmessage

// 服务器端 jsynchronous.onmessage(websocket, data); // 浏览器端 jsynchronous.onmessage(data);

一个函数。您需要在传输的数据到达时调用onmessage。

list

// 服务器或浏览器端 jsynchronous.list();

返回变量名称的数组。

variables

// 服务器或浏览器端 jsynchronous.variables();

返回一个对象,键值对应名称->同步变量。

垃圾回收

jsynchronous.pausegc(); // 暂停jsynchronous垃圾回收
jsynchronous.resumegc(); // 恢复暂停的垃圾回收
jsynchronous.rungc(); // 同步运行垃圾回收器,忽略暂停

传递给jsynchronous(data, name, options)的选项

{send: <function>}

用特定于同步变量的send函数覆盖jsynchronous.send。默认未定义。

{rewind: true}

开启回溯模式。参见上文关于回溯模式的文档。默认为false。

{one_way: true}

指示客户端只读取数据,不在应用程序级别传输任何握手、心跳或重新同步请求。如果网络连接断开导致不同步,尽可能继续处理更改。参见上文关于连接中断和重新同步的文档。默认为false。

{wait: true}

告诉jsynchronous延迟同步,直到在同步变量上调用$tart()。默认为false。

{buffer_time: <number>}

在向客户端传输同步数据之前等待的毫秒数。默认为0。

{history_limit: <number>}

历史记录的最大大小。回溯模式忽略这个数字,因为回溯模式保存所有历史记录。默认为100000。

保留字

将同步变量可用的任何方法名作为选项键传递,以将该保留字覆盖为您提供的字符串值。

例如,要将方法名.$on()更改为__on__(),在调用jsynchronous()时传入{$on: '__on__'}作为选项。这将在服务器和客户端上覆盖保留字。如果您预期根变量包含与现有保留字匹配的键,这很有用。

同步变量根级可用的方法

.$info()

客户端或服务器。返回一个对象,详细说明此同步变量的信息。对调试有用。

.$ync(websocket)

仅服务器。将客户端添加到监听器列表中。Websocket可以是字符串、数字或由您的websocket库提供的对象。Websocket必须是唯一标识客户端的值或引用。

.$unsync(websocket)

仅服务器。从客户端列表中移除websocket。客户端将不再接收任何更新。

.$copy()

服务器和客户端。返回同步变量的深度副本。返回的变量不同步。

.$on('changes', callback)

仅限客户端。创建一个事件监听器,在每批更改后触发回调。服务器事件将在未来版本中提供。

.$on('snapshot', callback)

仅限客户端。创建一个事件,在创建快照时触发回调,用于回溯模式。服务器事件将在未来版本中提供。

.$tart()

仅限服务器。与调用jsynchronous()时的{wait: true}选项一起使用,告诉jsynchronous开始将变量同步到已$ync的客户端。

.$listeners()

仅限服务器。您传入.$ync()调用的websocket列表。

.$napshot(name)

仅限服务器。创建快照,用于回溯模式。名称可以是数字或字符串。

.$rewind(name, [counter])

仅限客户端。名称可以是数字或字符串。返回一个非同步变量,其数据与创建该名称快照时同步变量的数据相匹配。如果未定义名称,将回溯到同步变量的编号变更计数器。服务器端回溯将在未来版本中提供。

常见问题

如何在React/Vue/Angular/Svelte中使用我的同步变量?

在同步变量的根上使用.$copy()来填充初始状态。

使用.$on('change')事件监听器来更新状态。

jsynchronous可以用来表示图形或复杂数据结构吗?

当然可以。无论是稀疏或密集的图形、树、链表、双向链表、循环和自引用数据结构,甚至可能是神经网络。如果JavaScript可以表示它,jsynchronous就可以轻松地同步它。

在笨重的传输栈表现力有限的世界中,jsynchronous旨在成为一股清新的空气,不限制您可以用它做什么。

jsynchronous真的可以用于游戏吗?

所有浏览器依赖的TCP/IP在丢包严重的情况下可能会因为队头阻塞而增加延迟。

对90%的游戏来说,基于TCP/IP的Jsynchronous是非常理想的。对于快速反应的射击游戏或格斗游戏可能不太适合。如果您的游戏不需要毫秒级精度,jsynchronous将以网络所能承载的最快速度将您的数据完美同步到每个客户端,您的websocket可以处理

UDP可能会进入浏览器,这对快节奏游戏来说非常令人兴奋。虽然UDP不适合精确的数据同步,因为它不能确保传输或排序,但Jsynchronous的one_way模式将非常适合快速的尽力而为传输。

我可以进行浏览器->服务器同步吗?

保护应用程序安全的最佳方法是构建API或使用websocket进行浏览器->服务器通信。

可以在浏览器中导入jsynchronous.js,在服务器上导入jsynchronous-client.js。每个浏览器都必须为其同步变量唯一命名,以便服务器能够区分它们。

对于视频游戏,游戏状态可以从服务器->浏览器同步,用户输入可以从浏览器->服务器同步。这样,您可以轻松地让游戏循环响应用户输入的变化并更新所有客户端可见的游戏状态。

任何好奇的脚本编写者都可以打开浏览器控制台并随意修改您的同步变量。jsynchronous服务器设计为在受信任的环境中运行,而浏览器不是。您的websocket服务器必须进行速率限制和大小限制(maxHttpBufferSize/maxPayload),如果数据结构与您的预期不完全匹配,应该断开连接。

双向同步和客户端的更改呢?

客户端数据结构的更改不会反映在服务器或其他客户端上,并可能导致错误。

Jsynchronous是单向同步,而不是双向同步。这可能在未来得到实验性支持,但对于生产工作负载,强烈建议使用API或websocket命令,让服务器从其端更改jsynchronous变量。

这样做的原因是,相比服务器API/接口,保护客户端数据结构免受篡改、注入、DDoS或放大攻击要困难得多。代理和getter/setter是相对较新的JavaScript规范,通过不接受来自客户端的更改,这个库可以更容易地支持非常旧的浏览器。

使用像jsynchronous这样的响应式数据结构来管理双向请求以更改数据存在局限性。即使是像多个客户端同时增加这样简单的操作,在最后写入胜出的启发式方法中也可能丢失,因为i++在getter/setter看来与i=常量相同。某些数据类型可能需要比"设置"和"删除"更具表现力的操作。操作转换需要针对应用程序、意图和数据类型来处理合并冲突,即使是服务器><客户端冲突,通过API也比通过响应式数据结构更容易推理。

支持Jsynchronous

想要提供帮助吗?考虑捐赠,所有收益都用于jsynchronous的开发。

如果您想为这个开源项目贡献代码,请联系我们

编辑推荐精选

Trae

Trae

字节跳动发布的AI编程神器IDE

Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。

AI工具TraeAI IDE协作生产力转型热门
问小白

问小白

全能AI智能助手,随时解答生活与工作的多样问题

问小白,由元石科技研发的AI智能助手,快速准确地解答各种生活和工作问题,包括但不限于搜索、规划和社交互动,帮助用户在日常生活中提高效率,轻松管理个人事务。

热门AI助手AI对话AI工具聊天机器人
Transly

Transly

实时语音翻译/同声传译工具

Transly是一个多场景的AI大语言模型驱动的同声传译、专业翻译助手,它拥有超精准的音频识别翻译能力,几乎零延迟的使用体验和支持多国语言可以让你带它走遍全球,无论你是留学生、商务人士、韩剧美剧爱好者,还是出国游玩、多国会议、跨国追星等等,都可以满足你所有需要同传的场景需求,线上线下通用,扫除语言障碍,让全世界的语言交流不再有国界。

讯飞智文

讯飞智文

一键生成PPT和Word,让学习生活更轻松

讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。

AI办公办公工具AI工具讯飞智文AI在线生成PPTAI撰写助手多语种文档生成AI自动配图热门
讯飞星火

讯飞星火

深度推理能力全新升级,全面对标OpenAI o1

科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。

热门AI开发模型训练AI工具讯飞星火大模型智能问答内容创作多语种支持智慧生活
Spark-TTS

Spark-TTS

一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型

Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。

咔片PPT

咔片PPT

AI助力,做PPT更简单!

咔片是一款轻量化在线演示设计工具,借助 AI 技术,实现从内容生成到智能设计的一站式 PPT 制作服务。支持多种文档格式导入生成 PPT,提供海量模板、智能美化、素材替换等功能,适用于销售、教师、学生等各类人群,能高效制作出高品质 PPT,满足不同场景演示需求。

讯飞绘文

讯飞绘文

选题、配图、成文,一站式创作,让内容运营更高效

讯飞绘文,一个AI集成平台,支持写作、选题、配图、排版和发布。高效生成适用于各类媒体的定制内容,加速品牌传播,提升内容营销效果。

热门AI辅助写作AI工具讯飞绘文内容运营AI创作个性化文章多平台分发AI助手
材料星

材料星

专业的AI公文写作平台,公文写作神器

AI 材料星,专业的 AI 公文写作辅助平台,为体制内工作人员提供高效的公文写作解决方案。拥有海量公文文库、9 大核心 AI 功能,支持 30 + 文稿类型生成,助力快速完成领导讲话、工作总结、述职报告等材料,提升办公效率,是体制打工人的得力写作神器。

openai-agents-python

openai-agents-python

OpenAI Agents SDK,助力开发者便捷使用 OpenAI 相关功能。

openai-agents-python 是 OpenAI 推出的一款强大 Python SDK,它为开发者提供了与 OpenAI 模型交互的高效工具,支持工具调用、结果处理、追踪等功能,涵盖多种应用场景,如研究助手、财务研究等,能显著提升开发效率,让开发者更轻松地利用 OpenAI 的技术优势。

下拉加载更多