Skip to content

Commit

Permalink
Merge branch 'master' into feat-rn-relations
Browse files Browse the repository at this point in the history
  • Loading branch information
CommanderXL committed Oct 30, 2024
2 parents 503e927 + 7518368 commit 4418593
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 34 deletions.
13 changes: 11 additions & 2 deletions packages/fetch/@types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,19 @@ interface CancelTokenClass {
}
}

export interface fetchOption extends WechatMiniprogram.RequestOption {
interface PreCacheOption<T> {
enable: boolean
ignorePreParamKeys?: string[]
equals?: (selfConfig: any, cacheConfig: any) => boolean
cacheInvalidationTime?: number
onUpdate?: (response: T) => void
}

export interface fetchOption<T> extends WechatMiniprogram.RequestOption {
params?: object
cancelToken?: InstanceType<CancelTokenClass>['token']
emulateJSON?: boolean
usePre?: PreCacheOption<T>
}

interface CreateOption {
Expand All @@ -17,7 +26,7 @@ interface CreateOption {
ratio?: number
}

type fetchT = <T>(option: fetchOption, priority?: 'normal' | 'low') => Promise<WechatMiniprogram.RequestSuccessCallbackResult<T> & { requestConfig: fetchOption }>
type fetchT = <T>(option: fetchOption<T>, priority?: 'normal' | 'low') => Promise<WechatMiniprogram.RequestSuccessCallbackResult<T> & { requestConfig: fetchOption<T> }>
type addLowPriorityWhiteListT = (rules: string | RegExp | Array<string | RegExp>) => void
type createT = (option?: CreateOption) => xfetch

Expand Down
62 changes: 58 additions & 4 deletions packages/fetch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,9 @@ mpx.xfetch.setValidator([
}
])
```

### 支持缓存请求
xfetch 支持配置 isPre=true 来缓存请求结果。设置 isPre=true 并发出首次请求后,在有效时间内的下一次请求,若参数和请求方法一致,则会直接返回上次请求的结果。参数或者请求方法不一致,以及不在有效时间内,都会重新请求并返回。默认缓存有效时间为 5000ms,也可通过 cacheInvalidationTime 配置。
xfetch 支持配置 usePre=true 来缓存请求结果。设置 usePre=true 并发出首次请求后,在有效时间内的下一次请求,若参数和请求方法一致,则会直接返回上次请求的结果。参数或者请求方法不一致,以及不在有效时间内,都会重新请求并返回。默认缓存有效时间为 3000ms
```js
mpx.xfetch.fetch({
url: 'http://xxx.com',
Expand All @@ -223,8 +224,61 @@ mpx.xfetch.fetch({
name: 'test'
},
// 是否缓存请求
isPre: true,
// 缓存有效时长
cacheInvalidationTime: 3000
usePre: true
})
```

usePre: true 是 usePre 的简写方式,用默认的 usePre.ignorePreParamKeysusePre.cacheInvalidationTime,下面代码与上面的代码等价
可通过 usePre.cacheInvalidationTime 参数配置缓存有效时间, 默认值为 3000
可通过 usePre.ignorePreParamKeys 来制定参数对比时忽略的key, 默认值为 []
可通过 usePre.equals 来自定义判定命中缓存的逻辑

```js
mpx.xfetch.fetch({
url: 'http://xxx.com',
method: 'POST',
data: {
name: 'test'
},
usePre: {
// 是否缓存请求
enable: true,
// 忽略对比的参数key,仅Object类型参数支持忽略不对比这些key的值
ignorePreParamKeys: [],
// 或者使用 equals,覆盖 ignorePreParamKeys
equals(selfConfig, cacheConfig) {
// return true 表示命中缓存
return JSON.stringify(selfConfig.params) === JSON.stringify(cacheConfig.params)
},
// 缓存有效时长
cacheInvalidationTime: 3000
}
})
```

**更加倾向于请求实时性的预先请求**

**更加倾向于请求实时性的预先请求**

在某些场景下(如耗时较长的页面跳转)我们期望能在提前发起请求作为缓存来加速进入页面的首次渲染,有需要能尽量保证数据的实时性时,可以传入 usePre.onUpdate 回调方法来获取最新的请求内容

usePre.onUpdate 开启后,如果本次请求命中的请求缓存,依然会再次发起请求,fetch 方法返回内容变为 Promise.race([缓存请求, 实时请求]),如果 缓存请求 先完成,则等待 实时请求 完成后,会将 实时请求 的返回内容作为 usePre.onUpdate 的参数进行回调。

```js
mpx.xfetch.fetch({
url: 'http://xxx.com',
method: 'POST',
usePre: {
// 是否缓存请求
enable: true,
onUpdate(response) {
// 使用实时请求数据,这里的 response 依然会经过 interceptors.response 处理
}
}
}).then(response => {
// 使用数据,可以通过 response.isCache 标识判断该结果是否来源于缓存
})
```

> tips: onUpdate 中的 response 也会经过 interceptors.response 处理,所以以上代码可能会触发两次 interceptors.response

17 changes: 11 additions & 6 deletions packages/fetch/src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,15 @@ function formatCacheKey (url) {
return url.split('//')[1].split('?')[0]
}

function checkCacheConfig (thisConfig, catchData) {
return compareParams(thisConfig.params, catchData.params, thisConfig.ignorePreParamKeys) &&
compareParams(thisConfig.data, catchData.data, thisConfig.ignorePreParamKeys) &&
thisConfig.method === catchData.method
function checkCacheConfig (thisConfig, cacheData) {
let paramsEquals = false
if (typeof thisConfig.usePre.equals === 'function') {
paramsEquals = thisConfig.usePre.equals(thisConfig, cacheData)
} else {
paramsEquals = compareParams(thisConfig.params, cacheData.params, thisConfig.usePre.ignorePreParamKeys) &&
compareParams(thisConfig.data, cacheData.data, thisConfig.usePre.ignorePreParamKeys)
}
return paramsEquals && thisConfig.method === cacheData.method
}

function compareParams (params, cacheParams, ignoreParamKeys = []) {
Expand All @@ -229,8 +234,8 @@ function compareParams (params, cacheParams, ignoreParamKeys = []) {
// ignoreParamKeys 字符串数组化
ignoreParamKeys = ignoreParamKeys.trim().split(',')
}
const paramsKeys = Object.keys(params)
const cacheParamsKeys = Object.keys(cacheParams)
const paramsKeys = Object.keys(params).filter(key => !ignoreParamKeys.includes(key))
const cacheParamsKeys = Object.keys(cacheParams).filter(key => !ignoreParamKeys.includes(key))
// key长度不等
if (paramsKeys.length !== cacheParamsKeys.length) {
return false
Expand Down
79 changes: 57 additions & 22 deletions packages/fetch/src/xfetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ export default class XFetch {
}
delete config.emulateJSON
}

if (!isObject(config.usePre)) {
config.usePre = {
enable: !!config.usePre
}
}
config.usePre.cacheInvalidationTime = config.usePre.cacheInvalidationTime || 3000 // 默认值3000
config.usePre.ignorePreParamKeys = config.usePre.ignorePreParamKeys || [] // 默认空数组
}

create (options) {
Expand Down Expand Up @@ -160,17 +168,19 @@ export default class XFetch {

checkPreCache (config) {
// 未设置预请求 则直接 return
if (!config.usePre) return false
if (!config.usePre.enable) return false
const cacheKey = formatCacheKey(config.url)
const cacheRequestData = this.cacheRequestData[cacheKey]
if (cacheRequestData) {
delete this.cacheRequestData[cacheKey]
const cacheInvalidationTime = config.cacheInvalidationTime || 3000
// 缓存是否过期 >3s 则算过期
if (Date.now() - cacheRequestData.lastTime <= cacheInvalidationTime &&
checkCacheConfig(config, cacheRequestData) &&
cacheRequestData.responsePromise) {
return cacheRequestData.responsePromise
// 缓存是否过期:大于cacheInvalidationTime(默认为3s)则算过期
const isNotExpired = Date.now() - cacheRequestData.lastTime <= config.usePre.cacheInvalidationTime
if (isNotExpired && checkCacheConfig(config, cacheRequestData) && cacheRequestData.responsePromise) {
return cacheRequestData.responsePromise.then(response => {
// 添加 isCache 标识该请求来源于缓存
return { ...response, isCache: true }
})
} else {
delete this.cacheRequestData[cacheKey]
}
}
const { params, data, method } = config
Expand All @@ -191,10 +201,6 @@ export default class XFetch {

fetch (config, priority) {
// 检查缓存
const responsePromise = this.checkPreCache(config)
if (responsePromise) {
return responsePromise
}
// middleware chain
const chain = []
let promise = Promise.resolve(config)
Expand All @@ -209,6 +215,13 @@ export default class XFetch {
// 5. 对于类POST请求将config.emulateJSON实现为config.header['content-type'] = 'application/x-www-form-urlencoded'
// 后续请求处理都应基于正规化后的config进行处理(proxy/mock/validate/serialize)
XFetch.normalizeConfig(config)

// 检查缓存
const responsePromise = this.checkPreCache(config)
if (responsePromise && typeof config.usePre.onUpdate !== 'function') {
return responsePromise
}

try {
const checkRes = this.checkValidator(config)
const isWrong = (typeof checkRes === 'boolean' && !checkRes) || (isObject(checkRes) && !checkRes.valid)
Expand All @@ -219,7 +232,38 @@ export default class XFetch {
console.log('xfetch参数校验错误', e)
}
config = this.checkProxy(config) // proxy
return this.queue ? this.queue.request(config, priority) : this.requestAdapter(config)

let promise = this.queue ? this.queue.request(config, priority) : this.requestAdapter(config)
// 后置拦截器
const chain = []
this.interceptors.response.forEach(function pushResponseInterceptors (interceptor) {
chain.push(interceptor.fulfilled, interceptor.rejected)
})
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift())
}

// 如果开启缓存,则将 promise 存入缓存
if (config.usePre.enable) {
const cacheKey = formatCacheKey(config.url)
this.cacheRequestData[cacheKey] && (this.cacheRequestData[cacheKey].responsePromise = promise)
}

// 如果命中缓存,则将缓存 responsePromise 与最新 promise 竞速,返回最快的 promise
if (responsePromise && typeof config.usePre.onUpdate === 'function') {
const returnPromise = Promise.any([responsePromise, promise])
returnPromise.then(response => {
if (response.isCache) { // 如果预请求先返回,则等待实际请求返回后回调 usePre.onUpdate
promise.then(response => {
// 回调 usePre.onUpdate
config.usePre.onUpdate(response)
})
}
})
return returnPromise
}

return promise
}

this.interceptors.request.forEach(function unshiftRequestInterceptors (interceptor) {
Expand All @@ -228,19 +272,10 @@ export default class XFetch {

chain.push(request, undefined)

this.interceptors.response.forEach(function pushResponseInterceptors (interceptor) {
chain.push(interceptor.fulfilled, interceptor.rejected)
})

while (chain.length) {
promise = promise.then(chain.shift(), chain.shift())
}

if (config.usePre) {
const cacheKey = formatCacheKey(config.url)
this.cacheRequestData[cacheKey] && (this.cacheRequestData[cacheKey].responsePromise = promise)
}

return promise
}
}

0 comments on commit 4418593

Please sign in to comment.