请教一个编程技巧,有没有办法把 websocket 的通讯装到 Promise 里面去?

2020-08-26 22:24:55 +08:00
 yazoox

现在有一个需求,要使用 websocket 传输数据,时间大概几秒钟。
想在传输数据的时候,同时装备下一份数据。准备的时候,也大概几秒钟。

所以,就在想,能否把这两块并行起来。

初步想法 /方法,就是用 Promise.all ,但貌似代码不是很好写。
因为 websocket 的调用,什么 onmessage 等等,不太好放入到 promise 里面去。

有没有兄弟知道怎么做?或者有其它更好的方法?比如 multi-threads?

谢谢。

p.s. JavaScript/TypeScript 前端

3100 次点击
所在节点    JavaScript
16 条回复
Jirajine
2020-08-26 22:34:18 +08:00
jiangzm
2020-08-26 22:51:47 +08:00
你弄个发送队列不就好了,ws 从队列拿数据发送,组装的数据不断扔到队列。

后面你要封装 Promise 是要干嘛,没看懂, 可以贴了伪代码示例一下。
fivge
2020-08-27 09:03:29 +08:00
rxjs
yazoox
2020-08-27 09:42:43 +08:00
@jiangzm #2 不太好贴。legacy 的项目,一大堆代码全挤在一起。

基本流程就是先传输文件过去,传输完了,如果成功,再传输证书。即,onmessage 里面,收到成功的回复后,再发送证书。

但大家知道,申请证书,调用 api 也是需要时间的。
所以,想在发送文件时,异步调用函数申请证书。等收到文件传输成功消息 /响应后,就能直接发送证书了。
yazoox
2020-08-27 09:47:36 +08:00
@jiangzm #2 看懂你的意思了。

可惜,我们这个逻辑 /流程,当初设计的时候,就有严格的顺序。握手-验证双方身份-发送文件-发送证书-……
有顺序的。相当于“同步”执行。
azcvcza
2020-08-27 10:02:55 +08:00
```
onmessage = function(data){
if(data.type === '某种类型'){
new Promise(resolve=>{
resolve(axios.post('xxx'))
}).then(res=>{
// get auth
websocket.send()
})
}
}
```
大致逻辑这样?
peterjose
2020-08-27 10:46:19 +08:00
没太听懂你在说啥 但是 rxjs-websocket 估计能满足你
libook
2020-08-27 11:13:16 +08:00
没有代码,没法提供方案。

数据量不大到至于爆掉引擎内存空间的话,可以准备两个线程(比如 Web Workers )、一个队列,一个线程持续准备数据并将待发送的数据插入到队列中,另一个线程不断从队列中读取数据发送。如果你用内存存储队列且怕内存爆掉,可以在准备数据的过程里每次循环都检查一下队列大小,如果超出阈值就暂停一段时间。

Promise 是在一个线程内控制异步 IO 的,Promise.all 不知道你想怎么用,如果单纯吧准备和发送数据的过程扔到里面估计是所有要处理的数据同时准备和发送了,你要是对数据没有先后顺序要求的话也不是不行。Promise 提升效率的关键在于异步 API 异步执行,同步 API 用了 Promise 也不会异步执行,这时候就得考虑多线程了。
hitaoguo
2020-08-27 11:24:45 +08:00
// 把传输文件封装成一个 Promise
const sendFile = () => Promise.resolve()
// 申请证书也封装一下
const requestCert = () => Promise.resolve()
const sendCert = () => { }
// 最后通过 Promise.All ,当文件传输好了,并且证书也申请下来了的时候,再发送证书
Promise.all([sendFile(), requestCert()]).then(sendCert)
qyvlik
2020-08-27 15:56:49 +08:00
jiangzm
2020-08-28 00:30:10 +08:00
@yazoox #4 这很简单啊,异步发送文件和异步请求证书就行,然后在 onmessage 里面同步等待请求证书的结果
code: https://gist.github.com/jiangzm/4474f2c2f601b23d306235b2233fbe03
preview: <img src="https://s1.ax1x.com/2020/08/28/d5rJOg.png" alt="d5rJOg.png" border="0" />
jiangzm
2020-08-28 00:34:50 +08:00
jiangzm
2020-08-28 00:35:50 +08:00
yazoox
2020-08-28 15:32:51 +08:00
@jiangzm
谢谢。你的这个方法是可以的。
今天学习到了一招,原来 promise 可以直接 assgin 给一个变量,调用后不管。
在后面需要的时候,await promise 变量就可以了。
yazoox
2020-08-31 10:17:47 +08:00
@jiangzm 这个方法,在使用过程中,还碰到一个问题。就是 try-catch 放在哪里?
我们并不能保证 requestCert 一定成功,所以,Promise 内部的调用可能需要错误处理, throw exception 。
错误捕获 /try-catch,是放在 L35 还是 L41 呢?因为 Promise 的启动和检查,分离了。
jiangzm
2020-08-31 21:25:05 +08:00
@yazoox #15 有两个改法,一是把 requestCert 里面 fetch 请求的 catch 加上,catch 里面 resolve 空字符串出来即可,还有种方式就是把 async-await 写法改成传统链式调用,即:certPromise.then(res => ws.send(cert)).catch(ex => console.log(ex));

另外对于不稳定或易超时的接口要加入重试机制

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/701731

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX