1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
| import { v4 as uuidv4 } from 'uuid' import {filter, firstValueFrom, fromEvent, interval, map, mergeMap, take} from 'rxjs'
const API_NAME_SPACE = 'STORAGE_REQUEST'
const STORAGE_API_ERR_CODE = -99999
const windowId = uuidv4()
const linkAPI = (apiName) => { return `${API_NAME_SPACE}_${apiName}` }
const addStorageListenerForOnce = async (storageName, element = window) => {
if (!storageName) { console.error('监听的storageName不能为空') return false }
const changeEvent = await firstValueFrom(fromEvent(element, 'storage') .pipe(filter(e => e.storageArea[storageName]), map(e => e.storageArea[storageName])))
console.log(`监听storage中的${storageName}变化触发了:`, changeEvent)
localStorage.removeItem(storageName)
return changeEvent }
export const storageRequest = async (apiName, apiParams) => {
const newReq = { name: apiName, params: apiParams, uid: `BSY_API_RES_${uuidv4()}`, windowId }
const currentQueueStr = localStorage.getItem(linkAPI(apiName))
let newQueueArr = []
try { newQueueArr = JSON.parse(currentQueueStr || '[]') } catch (e) { console.error('获取requestQueue时失败,', e) }
newQueueArr.push(newReq)
localStorage.setItem(linkAPI(apiName), JSON.stringify(newQueueArr))
const res = await addStorageListenerForOnce(newReq.uid)
return JSON.parse(res) }
const clearRequestQueue = (uid, storageName) => { let newCurrentStorage = localStorage.getItem(storageName)
if (newCurrentStorage) { const storageObj = JSON.parse(newCurrentStorage) const indexToClear = storageObj.findIndex(item => item.uid === uid)
if (indexToClear > -1) { storageObj.splice(indexToClear, 1)
newCurrentStorage = JSON.stringify(storageObj)
localStorage.setItem(storageName, newCurrentStorage) } }
return newCurrentStorage
}
export const addApiListener = (apiName, callback, element = window) => {
const storageName = linkAPI(apiName)
let currentStorage = localStorage.getItem(storageName) || '[]'
const resolveRequest = res => { const {name, uid, params} = res
let paramsArr = []
if (Array.isArray(params)) { paramsArr = params } else { paramsArr = params ? [params] : [] }
if (callback && uid) { const ret = callback(...paramsArr) if (ret instanceof Promise) { ret.then(pres => { if (pres) { localStorage.setItem(uid, JSON.stringify(pres)) } else { localStorage.setItem(uid, JSON.stringify({code: STORAGE_API_ERR_CODE})) } }).catch(e => { console.error('请求错误:', e) localStorage.setItem(uid, JSON.stringify({code: STORAGE_API_ERR_CODE, msg: e.msg || '未知错误'})) }) } else { localStorage.setItem(uid, JSON.stringify(ret)) } currentStorage = clearRequestQueue(uid, storageName) } }
const initStorageArr = JSON.parse(currentStorage)
if(initStorageArr.length) { initStorageArr.forEach(resolveRequest) }
const subscribe = fromEvent(element, 'storage').pipe( map(e => { return e.storageArea[storageName] }), filter(storagetStr => storagetStr && storagetStr !== currentStorage), map(storageStr => { if (currentStorage !== storageStr) {
let newStorageArr = JSON.parse(storageStr)
let currentStorageArr = JSON.parse(currentStorage || '[]')
const newReqs = newStorageArr.filter(item => item.windowId !== windowId && !currentStorageArr.some(req => req.uid === item?.uid))
currentStorage = storageStr
return newReqs } }), filter(newReqs => newReqs && newReqs.length), mergeMap(newReqs => { return interval(1).pipe(take(newReqs.length), map(i => newReqs[i])) }) ).subscribe(resolveRequest)
return subscribe }
|