需求
页面需要对接本地门禁读卡器,实现门禁卡读写功能。
当前门禁卡通过本地服务插件与页面建立 websorcet 通信, 实现读写卡操作。
问题
通信响应需要通过监听回调函数, 更具对应的类型及自定义UID 判断处理方式。
造成调用与响应处理业务逻辑的分离,当前希望实现类型, 接口调用的模式。将调用与处理逻辑聚合在一起。
例子
代码语言:javascript复制const ws = new WebSocket("ws://127.0.0.1:3000")
const promiseTask = new CallbackToPromiseTask()
promiseTask.clear()
// 绑定监听
wx.onmessage(response =>{
const { resolve, reject } = promiseTask.shift(response.UID)
if(response.err){ reject(response.err); return }
resolve(response)
})
const send = async (data) => {
const [ task, UID ] = promiseTask.push()
wx.send({ ...data, UID })
const back = awiat task
console.log(back)
}
实现
代码语言:javascript复制/**
* 计数器
*/
class Counter {
constructor(initNum=-1){
this._initNum = initNum
this._count = initNum
}
get count() {
return this._count
}
add (){
this._count =1
return this
}
reset(){
this._count = this._initNum
return this
}
static create(...args){
return new Counter(...args)
}
}
/**
* 响应回调转 promise 任务队列
* @prop _count
*/
export class CallbackToPromiseTask {
static create(...args){
return new CallbackToPromiseTask(...args)
}
constructor(counter=Counter){
this._counter = counter.create() // 计数器,生产任务编号
this._tasks = new Map() // 任务池
this._keys = [] // 编号队列
}
_reset(){
this._counter.reset()
this._tasks = new Map()
this._keys = []
}
/**
* 添加任务
* @param { any } data 默认回传参数
* @returns [ Promise, key ] [ 等待响应 promise 对象, 任务编号 ]
*/
push (data){
const _this = this
const _key = this._counter.add().count
_this._keys.push(_key)
return [
new Promise((resolve, reject) =>{
_this._tasks.set( _key, { resolve, reject, data, _key })
}),
_key
]
}
/**
* 调出任务
* @param { any } key 任务编号
* @param { function } notFind 查询任务失败回调
* @returns { task | undefined } 返回缓存的任务对象
*/
shift(key, notFind){
if(key !== undefined){
this._keys = this._keys.filter(item => item !== key)
}else{
key = this._keys.shift()
}
if(!this._tasks.has(key)){
if(!notFind){
console.error(`task ${key} is undefined`)
}else{
notFind(key)
}
return
}
const task = this._tasks.get(key)
this._tasks.delete(key)
return task
}
// 清除调用
clear(type='reject'){
this._tasks.forEach((item, key) => {
item[type](item.data)
})
this._reset()
}
/**
* 快速执行队列任务
* 根据任务编号取的任务并使用,默认参数执行
* 类似模拟单一顺序执行任务
*/
run(){
const task = this.shift()
task.resolve(task.data)
}
}