因何而生
陆游说的好,“山穷水尽疑无路,柳暗花明又一村”。
有一段时间因为别的事情都没接触前端了,之前也没有写博客的习惯,所以很多踩过的坑又结结实实的再踩了一遍。最近遇到了这么个需求,需要在多个页面保持对特定状态的控制。之前做原型测试时只做了单页面的测试,没考虑到在页面里定义连接的话跨页会失效的问题,由此有了以下的改进思路。
此文仅为记录思路的雏形,若能有更好的思路欢迎指教交流。
思路
要想 websocket 连接一直保持,必须将连接挂在全局上。回想起使用 Vue 做单页应用时候就是把连接挂在全局解决的,那这里是不是可以照搬这个思路呢?
经过严丝合缝的思索(疯狂研究文档),有了如下思路:
/* App.js */
let SocketTask;
let socketPath;
//注意在Launch阶段执行连接
onLaunch: function () {
const that = this;
let val = that.data.val;
that.websocket(socketPath, val)
},
websocket(url, data) {
const that = this;
SocketTask = wx.connectSocket({
url: url,
data: data,
header: { 'content-type': 'application/x-www-form-urlencoded' }, //不知为何java后端需要设置此项才能正常通信
method: 'post',
success: res => {
console.log('WebSocket connect', res);
},
fail: err => {
console.log('出现错误啦!!' + err);
wx.showToast({
title: '网络异常!',
})
}
})
},
//将连接所需参数暴露到全局,此方法可自定义或取消
wsReconnect() {
const that = this;
that.websocket(socketPath, that.data.val);
}
globalData: {
SocketTask: SocketTask
}
此时已经完成了在全局创建一个 websocket 连接了,连接完成后可以把连接的状态管理器通过 globalData 方法暴露到全局,在 page 中可以通过该状态管理器实际操作 websocket 连接。
/* page */
const app = getApp();
const SocketTask = app.globalData.SocketTask;
onShow: function () {
const that = this;
SocketTask.onOpen(open=> {
console.log("Websocket open");
//...do something
});
SocketTask.onClose(close=> {
console.log("Websocket close");
app.wsReconnect();
//...do something
});
SocketTask.onError(err=> {
console.log(err);
wx.showToast({ title: err});
//...do something
});
SocketTask.onMessage(val=> {
console.log(val);
//...do something
})
},
至此扩展已经可以正常使用 websocket 处理我们的业务逻辑了。
如果你的程序足够复杂,完全可以把这一部分抽象出来单独成为一个 websocket 连接处理模块,小程序的api在方便开发的同时仿佛也给开发套上了一层不轻的枷锁。
结语
条条大路通罗马,解决问题的方法往往不止一种,所谓的最优解也可能是暂时的最优。
只有解决问题,才是程序设计的最终追求。
Clancy Lin
2019.1.15
I can be whatever I want to be
****2019.2.7更新*****
为了更好的利用小程序更新的 SocketTask, 更好的思路是在全局开启一个 websocket 连接并赋值给一个全局变量进行管理,这样就可实现在全局或者不同页面间监听开启关闭的需求。
但是同时这样设置又会出现一个新的问题,在不同页面里放置的监听器在页面跳转后仍然存在,在微信没有对这个问题进行修正的前提下我的解决思路是自己实现一个类路由卫士的小插件,每次监听时判断当前的页面路由,以实现不同的业务逻辑。
当然,如果逻辑复杂的话,完全可以将监听抽象成一个独立的解决插件,监听到全局并在每次路由变化时跟路由卫士小插件协作完成操作。