|
本帖最后由 kongkongye 于 2018-10-31 16:42 编辑
快应用版本: 1020
在使用web组件进行快应用与网页间的通信的时候,有这几个发现:- 运行'npm run watch'时会提示web组件不支持message事件,但实际上是支持的(只是提示上的小问题)
- 快应用发信息到网页,与网页发信息到快应用,用的方法名都是postMessage,但数据格式并不一致,使用起来不方便
- 消息会丢失(比如网页端消息处理函数还没执行到就给网页发信息等情况)
- 网页给快应用发信息时,快应用发送给网页的信息才会带回
因此,这里花了点力气,做了个辅助的库,特点:
- 消息有序发送
- 消息不会丢失,保证到达
- 消息不会接收多次(去重)
- 消息分类型,类似事件的监听机制,更加方便
快应用里,新建一个channel.js文件,内容:
-
- /**
- * 通道,用来与html进行可靠的通信
- *
- * 1. 有序
- * 2. 回传与ack机制,保证到达
- * 3. id验证机制,去重
- *
- * @param thisObj {Object} this对象
- * @param webId {String} web的id
- * @param timeout {Number} 超时时间,超时后会重试,单位ms,默认1000
- */
- var Channel = function (thisObj, webId, timeout) {
- timeout = timeout || 1000
-
- var that = this
-
- var debug = (...msgs) => console.debug.apply(null, ['[通道]', ...msgs])
- var log = (...msgs) => console.log.apply(null, ['[通道]', ...msgs])
- var error = (...msgs) => console.error.apply(null, ['[通道]', ...msgs])
-
- //消息id生成器
- that.idGenerator = 0
- //消息发送队列
- that.sendQueue = [
- // {
- // data: {},
- // resolve: Object,
- // },
- ]
- //***列表
- that.listeners = {
- // type: [listener1, listener2],
- }
-
- //当前接收的消息id
- that.receivedId = 0
-
- /**
- * @param type {String} 消息类型
- * @param data {Object} 消息内容
- * @return {Promise}
- */
- that.sendMsg = function (type, data) {
- var resolve;
- var promise = new Promise(resolve_ => resolve = resolve_)
- that.sendQueue.push({
- data: {
- pType: 'msg',
- id: ++that.idGenerator,
- type: type,
- data: data,
- },
- resolve
- })
- return promise
- }
-
- /**
- * 监听
- * @param type 消息类型
- * @param callback 回调
- */
- that.on = function (type, callback) {
- var typeListeners = that.listeners[type] || []
- that.listeners[type] = typeListeners
- typeListeners.push(callback)
- }
-
- /**
- * 收到消息时调用(设置web组件的message事件的处理函数)
- */
- that.onMsg = function ({message, url}) {
- debug('[收到消息]', message, '('+url+')')
- var {pType, id, type, data} = JSON.parse(message)
-
- if (pType === 'ack') {//ack包
- if (id === that.idGenerator) {//是当前的ack,有效,删除元素
- var nowPackets = that.sendQueue.splice(0, 1);
- that.valid_(nowPackets.length === 1)
- nowPackets[0].resolve()
- }
- }else if (pType === 'msg') {//正常消息
- if (id === that.receivedId+1) {//是下个准备接收的包,有效
- //更新缓存值
- that.receivedId++
- //处理
- var typeListeners = that.listeners[type] || []
- log('[处理消息]', '类型: '+type, '处理器数量: '+typeListeners.length)
- for (var i=0;i<typeListeners.length;i++) {
- try {
- typeListeners[i](data)
- } catch (e) {
- error('[处理器错误]', e)
- }
- }
- //响应ack
- that.send_({
- pType: 'ack',
- id,
- })
- }
- }else {//没有pType,当作ping包处理,忽略
- return
- }
- }
-
- /**
- * 发包
- */
- that.send_ = function (packet) {
- var str = JSON.stringify(packet)
- thisObj.$element(webId).postMessage({
- message: str
- })
- debug('[发送消息]', str)
- }
-
- /**
- * 下个包
- */
- that.next_ = function() {
- if (that.sendQueue.length > 0) {
- that.send_(that.sendQueue[0].data)
- }
- }
-
- /**
- * 验证
- */
- that.valid_ = function(bool, errMsg) {
- if (!bool) {
- throw new Error(errMsg || 'Valid Fail!')
- }
- }
-
- //计时器: 不断重试发送包
- var timerId = setInterval(function () {
- if (thisObj.$valid) {//仍然有效
- that.next_()
- }else {//取消计时器
- log('已经失效,取消计时器')
- clearInterval(timerId)
- }
- }, timeout)
- }
-
- module.exports = Channel
复制代码
快应用端使用方式(参考):
-
- <template>
- <web id="web" src="xxx" @message="{{onMessage}}"></web>
- </template>
-
- <script>
- import Channel from './channel'
-
- export default {
- channel: null,
- onInit() {
- this.channel = new Channel(this, 'web')
-
- //通道监听
- this.channel.on('type1', function (data) {
- //处理收到的数据
- })
-
- //发送信息
- this.channel.sendMsg('type2', {
- //数据
- })
- },
- onMessage(param) {
- this.channel.onMsg(param)
- },
- }
- </script>
-
复制代码
网页端js(可以新建一个js或复制到script脚本里):
-
- /**
- * (在html端,实际上一个页面只能new一个通道)
- *
- * 通道,用来与html进行可靠的通信
- *
- * 1. 有序
- * 2. 回传与ack机制,保证到达
- * 3. id验证机制,去重
- *
- * @param logger {Function} 日志记录器,可为null
- * @param timeout {Number} 超时时间,超时后会重试,单位ms,默认1000
- */
- var Channel = function (logger, timeout) {
- timeout = timeout || 1000
-
- if (!logger) logger = () => {}
-
- var that = this
-
- //消息id生成器
- that.idGenerator = 0
- //消息发送队列
- that.sendQueue = [
- // {
- // data: {},
- // resolve: Object,
- // },
- ]
- //***列表
- that.listeners = {
- // type: [listener1, listener2],
- }
-
- //当前接收的消息id
- that.receivedId = 0
-
- /**
- * @param type {String} 消息类型
- * @param data {Object} 消息内容
- * @return {Promise}
- */
- that.sendMsg = function (type, data) {
- var resolve;
- var promise = new Promise(resolve_ => resolve = resolve_)
- that.sendQueue.push({
- data: {
- pType: 'msg',
- id: ++that.idGenerator,
- type: type,
- data: data,
- },
- resolve
- })
- return promise
- }
-
- /**
- * 监听
- * @param type 消息类型
- * @param callback 回调
- */
- that.on = function (type, callback) {
- var typeListeners = that.listeners[type] || []
- that.listeners[type] = typeListeners
- typeListeners.push(callback)
- }
-
- /**
- * 收到消息时调用(设置为onmessage的处理函数)
- */
- that.onMsg = function (message) {
- logger('[收到消息]' + message)
- var {pType, id, type, data} = JSON.parse(message)
-
- if (pType === 'ack') {//ack
- if (id === that.idGenerator) {//是当前的ack,有效,删除元素
- var nowPackets = that.sendQueue.splice(0, 1);
- that.valid_(nowPackets.length === 1)
- nowPackets[0].resolve()
- }
- } else if (pType === 'msg') {//正常消息
- if (id === that.receivedId + 1) {//是下个准备接收的包,有效
- //更新缓存值
- that.receivedId++
- //处理
- var typeListeners = that.listeners[type] || []
- logger('[处理消息]类型: ' + type + ' 处理器数量: ' + typeListeners.length)
- for (var i = 0; i < typeListeners.length; i++) {
- try {
- typeListeners[i](data)
- } catch (e) {
- logger('[处理异常]'+JSON.stringify(e))
- }
- }
- //响应ack
- that.send_({
- pType: 'ack',
- id,
- })
- }
- } else {//没有pType,忽略
- return
- }
- }
-
- /**
- * 发包
- */
- that.send_ = function (packet) {
- var str = JSON.stringify(packet)
- system.postMessage(str)
- logger('[发送消息]' + str)
- }
-
- /**
- * 下个包
- */
- that.next_ = function () {
- if (that.sendQueue.length > 0) {
- that.send_(that.sendQueue[0].data)
- }
- }
-
- /**
- * 验证
- */
- that.valid_ = function (bool, errMsg) {
- if (!bool) {
- throw new Error(errMsg || 'Valid Fail!')
- }
- }
-
- //计时器: 不断重试发送包
- setInterval(function () {
- that.next_()
- }, timeout)
-
- //计时器: ping
- //(必须不断地ping,因此html不发请求到app,那么app发送给html的消息就不会过来,蛋疼)
- setInterval(function () {
- that.send_({})
- }, 200)
-
- //对接
- system.onmessage = that.onMsg
- }
复制代码
网页端使用方法(参考):
-
- var channel = new Channel()
-
- //通道监听
- channel.on('type1', function (data) {
- //处理收到的数据
- })
-
- //发送信息
- channel.sendMsg('type2', {
- //数据
- })
复制代码
- 快应用发信息到网页,官方文档写的信息格式是messageString,但这个东西文档里并没说格式是怎样的,也搜不到,最后在官方的demo里,注释的代码里发现格式是{message: 'xxx'},非常坑爹
- 网页端的日志不好显示
|
|