简介
当页面复杂时,出现重复请求的概率还是很大的,如何比较优雅的处理,是我们必须要考虑的,这里提供了一种方案,个人认为是比较好的一个方案。可以作为参考。
方案
重复请求阻塞,等待相同请求的返回值
当多个同样的请求发出时,只有第一个会真正到达后端,其余几个阻塞,当第一个请求返回时,将返回值赋给其他正在阻塞的请求。
具体方法就是若判断有相同的请求正在执行中,将返回request请求返回的promise中的resolve和reject函数保存下来,待相同的请求返回,执行保存的resolve或reject函数,将返回值当做参数传入。
代码实现
// request.js
export default function request(
url,
{
method = 'post',
timeout = TIMEOUT,
prefix = HOME_PREFIX,
data = {},
headers = {},
dataType = 'json',
onUploadProgress,
}
) {
return new Promise((resolve, reject) => {
const baseURL = autoMatchBaseUrl(prefix)
headers = {
// 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Content-Type': 'application/json; charset=UTF-8',
...headers,
}
const defaultConfig = {
baseURL,
url,
method,
params: data,
data: data,
timeout,
headers,
responseType: dataType,
}
const requestingKey = generatePendingKey(defaultConfig)
// 有同样的请求正在执行,等待执行完一起返回
if (hasPendings(requestingKey)) {
addPending(requestingKey, resolve, reject)
console.log('requestingKey', requestingKey, getPendings(requestingKey))
} else {
// 正常请求
addPending(requestingKey, resolve, reject)
return axios(defaultConfig).then(
function(res) {
// 当页面切换时,会清除pending,所以这里获取到的值可能为空。
const pendings = getPendings(requestingKey)
if (pendings) {
pendings.forEach((item) => item.resolve(res))
removePending(requestingKey)
// 相关页面逻辑
}
},
function(err) {
// 当页面切换时,会清除pending,所以这里获取到的值可能为空。
const pendings = getPendings(requestingKey)
if (pendings) {
pendings.forEach((item) => item.reject(err))
removePending(requestingKey)
// 相关页面逻辑
}
}
)
}
})
}
// pending.js
import Qs from 'qs'
import { isEmpty } from '@/common/help'
const requestingMap = new Map()
/**
* 添加请求
* @param {Object} config
*/
const addPending = (requestingKey, resolve, reject) => {
if (hasPendings(requestingKey)) {
requestingMap.get(requestingKey).push({
resolve,
reject,
})
} else {
requestingMap.set(requestingKey, [
{
resolve,
reject,
},
])
}
}
/**
* 移除请求
* @param {Object} config
*/
const removePending = (requestingKey) => {
requestingMap.delete(requestingKey)
}
const getPendings = (requestingKey) => {
return requestingMap.get(requestingKey)
}
const hasPendings = (requestingKey) => {
return requestingMap.has(requestingKey)
}
/**
* 合成pending的key方法
*/
const generatePendingKey = (config) => {
const keys = [config.method, config.url, Qs.stringify(config.params)]
if (!isEmpty(config.data)) {
keys.push(Qs.stringify(config.data))
}
return keys.join('&')
}
export {
getPendings,
hasPendings,
addPending,
removePending,
generatePendingKey,
}