内容简介:微信基础库1.7.0之后的版本提供了新版的WebSocket API,考虑到兼容性问题,尝试整合新旧两种版本的API,进行简单的封装。从以下几个角度对微信小程序中所提供的WebSocket API封装支持1.7.0+,连接后会返回一个SocketTask对象,在该对象上监听该连接的各种事件与执行发送消息等操作。
微信基础库1.7.0之后的版本提供了新版的WebSocket API,考虑到兼容性问题,尝试整合新旧两种版本的API,进行简单的封装。
从以下几个角度对微信小程序中所提供的WebSocket API封装
- API兼容性
- 重连机制
小程序WebSocket API
旧版WebSocket API的使用
- 创建 - wx.connectSocket
- 发送消息 - sendSocketMessage
- 监听事件 - onSocketOpen
let socketOpen = false const socketMsgQueue = [] // 连接socket wx.connectSocket({ url: 'test.php' }) // 监听打开事件 wx.onSocketOpen(function(res) { socketOpen = true for (let i = 0; i < socketMsgQueue.length; i++){ sendSocketMessage(socketMsgQueue[i]) } socketMsgQueue = [] }) // 发送消息 function sendSocketMessage(msg) { if (socketOpen) { wx.sendSocketMessage({ data:msg }) } else { socketMsgQueue.push(msg) } }
新版WebSocket API的使用
支持1.7.0+,连接后会返回一个SocketTask对象,在该对象上监听该连接的各种事件与执行发送消息等操作。
let socketTask = wx.connectSocket({ url: 'test.php' }) // 监听打开事件 socketTask.onOpen(function(res) { socketOpen = true // 发送信息 socketTask.send({msg: "hello world"}) })
并发数
-
1.7.0
及以上版本,最多可以同时存在5
个WebSocket
连接。 -
1.7.0
以下版本,一个小程序同时只能有一个WebSocket
连接,如果当前已存在一个 WebSocket 连接,会自动关闭该连接,并重新创建一个WebSocket
连接。
模块封装
简单封装封装一个兼容新旧socketAPI的模块,仅考虑存在单个socket连接的情况
创建与事件监听
- 新版: 在socket连接时会返回一个socketTask对象,监听事件是在该对象的基础上进行
- 旧版: 直接使用wx放进行创建与监听方法
统一创建与添加监听函数
init() { let st = this.connect() this.listen(st) this.manualClose = false }
创建连接
connect() { let st = wx.connectSocket(this.config.server) return st }
添加事件监听函数
listen(st) { if (st !== undefined) { this.ws = st this.ws.onOpen(() => this.openHandle()) this.ws.onError(() => this.errorHandle()) this.ws.onClose(() => this.closeHandle()) this.ws.onMessage(res => this.messageHandle(res)) } else { wx.onSocketOpen(() => this.openHandle()) wx.onSocketError(() => this.errorHandle()) wx.onSocketClose(() => this.closeHandle()) wx.onSocketMessage(res => this.messageHandle(res)) } }
重连机制
预设标记位
retryLock = false; // 避免多次同时重连 socketOpen = false; // 连接状态 manualClose = false; // 主动断开标记
在连接关闭监听函数中执行重连
closeHandle() { console.info('WebSocket closed') this.socketOpen = false this.retryLock = false // 不论是error还是close都会触发close事件,统一在这里进行重连 // 初次连接失败不进行重连(失败不会进入到onOpen的监听事件中,那时未声明retryTimes变量) this.retryTimes !== undefined && this.reconnect() }
判断重连锁与是否主动断开进行重连
reconnect() { if (this.retryLock) return this.retryLock = true // 若manualClose为true,表明不是主动断开 if (!this.manualClose) { // 开始重连 setTimeout(() => { this.retry() }, this.retryInterval) } }
重连函数,包含重连次数的限制
retry() { if ( this.socketOpen || (this.retryTimes > 0 && this.retryCount <= this.retryTimes) ) { console.warn(`reconnect ending. reconnect ${this.retryTimes} times`) if (!this.socketOpen) { this.config.closeCallback() } return } this.retryTimes += 1 console.warn(`[ ${this.retryTimes} ]th reconnect WebSocket...`) this.init() }
消息队列
添加消息队列,当重连后自动发送缓存消息
openHandle() { this.retryTimes = 0 this.socketOpen = true this.retryLock = false this.messageQueue.map(e => this.send(e)) this.messageQueue = [] }
若发送时断开则先将消息缓存到消息队列中
send(value) { let data = this.msgWrapper(value) data = JSON.stringify(data) if (!this.socketOpen) { this.messageQueue.push(data) } else { if (this.ws) { this.ws.send({ data }) } else { wx.sendSocketMessage({ data }) } } }
辅助函数
添加一些包裹消息格式的 工具 函数
messageIndex = 0; helper = { isPlainObject: val => Object.prototype.toString.call(val) === '[object Object]', nextId: () => { this.messageIndex += 1 return this.messageIndex }, id: () => Date.now() + '.' + this.helper.nextId() }; msgWrapper(data) { let msg = data if (this.helper.isPlainObject(msg)) { if (msg.type) { return msg } else { return this.msgWrapper({ type: 'message', msg, id: this.helper.id() }) } } else { return this.msgWrapper({ type: 'message', msg, id: this.helper.id() }) } }
完整代码
export default class WXWebSocket { messageQueue = []; // 消息队列 retryLock = false; // 避免多次同时重连 socketOpen = false; manualClose = false; // 主动断开标记 constructor(config) { this.config = config || {} // 重连间隔 this.retryInterval = this.config.retryInterval && this.config.retryInterval > 100 ? this.config.retryInterval : 3000 // 重连次数 this.retryCount = this.config.retryCount || 5 this.init() } init() { let st = this.connect() this.listen(st) this.manualClose = false } connect() { let st = wx.connectSocket(this.config.server) console.log('current socket: ', st) return st } listen(st) { // 添加监听事件 if (st !== undefined) { // 若存在SocketTask,则要通过readyState判断状态 // CONNECTING: 0 // OPEN: 1 // CLOSING: 2 // CLOSE: 3 this.ws = st this.ws.onOpen(() => this.openHandle()) this.ws.onError(() => this.errorHandle()) this.ws.onClose(() => this.closeHandle()) this.ws.onMessage(res => this.messageHandle(res)) } else { wx.onSocketOpen(() => this.openHandle()) wx.onSocketError(() => this.errorHandle()) wx.onSocketClose(() => this.closeHandle()) wx.onSocketMessage(res => this.messageHandle(res)) } } close() { this.manualClose = true if (this.ws) { this.ws.close() } else { wx.closeSocket() } } send(value) { console.log('send value: ', value) let data = this.msgWrapper(value) data = JSON.stringify(data) if (!this.socketOpen) { // add new message to queue this.messageQueue.push(data) } else { if (this.ws) { this.ws.send({ data }) } else { wx.sendSocketMessage({ data }) } } } openHandle() { console.info('WebSocket connected') this.retryTimes = 0 this.socketOpen = true this.retryLock = false this.messageQueue.map(e => this.send(e)) this.messageQueue = [] } errorHandle() { console.error('WebSocket error') this.socketOpen = false } closeHandle() { console.info('WebSocket closed') this.socketOpen = false this.retryLock = false // 不论是error还是close都会触发close事件,统一在这里进行重连 // 初次连接失败不进行重连(失败不会进入到onOpen的监听事件中,那时未声明retryTimes变量) this.retryTimes !== undefined && this.reconnect() } reconnect() { if (this.retryLock) return this.retryLock = true // 若manualClose为true,表明不是主动断开 if (!this.manualClose) { // 开始重连 setTimeout(() => { this.retry() }, this.retryInterval) } } retry() { if ( this.socketOpen || (this.retryTimes > 0 && this.retryCount <= this.retryTimes) ) { console.warn(`end reconnect. reconnect ${this.retryTimes} times`) if (!this.socketOpen) { this.config.closeCallback() } return } this.retryTimes += 1 console.warn(`[ ${this.retryTimes} ]th reconnect WebSocket...`) this.init() } messageHandle(res) { this.config.responseCallback(res) } msgWrapper(data) { let msg = data if (this.helper.isPlainObject(msg)) { if (msg.type) { return msg } else { return this.msgWrapper({ type: 'message', msg, id: this.helper.id() }) } } else { return this.msgWrapper({ type: 'message', msg, id: this.helper.id() }) } } messageIndex = 0; helper = { isPlainObject: val => Object.prototype.toString.call(val) === '[object Object]', nextId: () => { this.messageIndex += 1 return this.messageIndex }, id: () => Date.now() + '.' + this.helper.nextId() }; }
使用
创建连接
let socketTask = new WXWebSocket({ server: this.wsServerOption, responseCallback: e => { let { data } = e let { msg } = JSON.parse(data) this.msgStack.push(msg) }, closeCallback: () => { this.socketTask = null } }) this.socketTask = socketTask
发送消息
sendWSMessage(msg) { this.msgStack.push(msg) this.socketTask && this.socketTask.send(msg) },
关闭连接
closeWS() { if (!this.socketTask) return if (this.socketTask.socketOpen) { this.socketTask.close() this.socketTask = null } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 小程序优化实践
- 小程序webview应用实践
- 编程日历小程序,对小程序云开发和生成海报的实践
- 给小程序再减重 30% 的秘密(京喜小程序首页瘦身实践)
- 程序员必备,“向上管理” 实践指南
- Clojure 并发实践:使用 pmap 加速程序
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
与孩子一起学编程
[美] 桑德Warren Sande、Carter Sande / 苏金国、姚曜 等 / 人民邮电出版社 / 2010-11 / 65.00元
一本老少咸宜的编程入门奇书!一册在手,你完全可以带着自己的孩子,跟随Sande父子组合在轻松的氛围中熟悉那些编程概念,如内存、循环、输入和输出、数据结构和图形用户界面等。这些知识一点儿也不高深,听起来备感亲切,书中言语幽默风趣而不失真义,让学习过程充满乐趣。细心的作者还配上了孩子们都喜欢的可爱漫画和经过运行测试的程序示例,教你用最易编写和最易理解的Python语言,写出你梦想中的游戏程序。 ......一起来看看 《与孩子一起学编程》 这本书的介绍吧!