背景
项目中接入三维模型,由于三维模型团队只提供iframe方式接入和postMessage通讯方式和通讯的数据格式。
// api调用的接口
// params 传递参数
{
require: {
api: Strubg,
params: *
}
}
刚开始的样子
<div class="model">
<iframe src="xxx" ref="iframe" />
</div>
created() {
this.initEvent()
},
methods: {
initEvent() {
window.addEventListener(
'message',
this.handleReceive,
false
)
this.$once('hook:beforeDestroy', () => {
window.removeEventListener(
'message',
this.handleReceive,
false
)
})
},
// 接收事件
handleReceive(e) {
console.log(e)
// e.data 就是接收的数据
},
// 发送事件
postMessage({ api, params }) {
const mergeParams = {
require: {
api,
params
}
}
this.$refs.iframe.contentWindow.postMessage(mergeParams, '*')
}
}
// 使用的时候
this.postMessage({
api: 'setData'
})
简单实现一下,但是发现不能直接拿到调用接口的返回值,只能通过handleReceive
接收值,并回调,这样子很麻烦。
promise改造
思路整理
需要跟三维模型团队约定uuid。
// queue.js
/**
* 异步队列
* @param time - 超时时间,单位秒
*/
export default class QueuePromise {
constructor(time = 15) {
this.queue = new Map()
this.time = time
}
// 加入队列
push(uuid, resolve, reject) {
const params = { uuid, resolve, reject }
params.timer = setTimeout(() => {
this.put(uuid)
reject({ code: -1, msg: '超时' })
}, this.time * 1000)
this.queue.set(uuid, params)
}
// 执行队列,并出栈
perform(uuid, params) {
const apiQueue = this.put(uuid)
// 这里执行resolve,并把结果返回回去
apiQueue.resolve(params)
}
// 找到并出栈
put(uuid) {
const apiQueue = this.queue.get(uuid)
if (!apiQueue) return
this.queue.delete(uuid)
apiQueue.timer && clearTimeout(apiQueue.timer)
return apiQueue
}
clear() {
this.queue.forEach(e => {
e.timer && clearTimeout(e.timer)
})
this.queue = null
}
}
+ import Queue from './queue'
created() {
this.initEvent()
},
methods: {
initEvent() {
+ this.queue = new Queue()
window.addEventListener(
'message',
this.handleReceive,
false
)
this.$once('hook:beforeDestroy', () => {
window.removeEventListener(
'message',
this.handleReceive,
false
)
+ this.queue && this.queue.clear()
})
},
// 接收事件
handleReceive(e) {
console.log(e)
// e.data 就是接收的数据
+ const { api, params, uuid } = e.data?.require || {}
+ if (uuid) return this.queue.perform(uuid, params) // 如果有uuid,则去执行resolve或者reject
// 正常处理你的业务
},
// 发送事件
postMessage({ api, params }) {
+ return new Promise((resolve, reject) => {
const mergeParams = {
require: {
api,
params
}
}
+ this.$refs.iframe.contentWindow.postMessage(mergeParams, '*')
+ this.queue.push(objRequest.require.uuid, resolve, reject)
+ })
}
}
// 使用的时候
this.postMessage({
api: 'setData'
}).then(e => { // 拿到返回值
console.log(e)
})
// 或者
const res = await this.postMessage({
api: 'setData'
})
以上就是postMessage
的Promise
化全过程。