提交 52a39440 编写于 作者: fxy060608's avatar fxy060608

feat(h5): add interceptor

上级 9b08d6ba
......@@ -240,6 +240,9 @@ export function wrapperUnimplemented (name) {
}
export function wrapper (name, invokeMethod, extras) {
if (!isFn(invokeMethod)) {
return invokeMethod
}
return function (...args) {
if (isSyncApi(name)) {
if (validateParams(name, args, -1)) {
......
import {
isFn,
isPlainObject
} from 'uni-shared'
import {
shouldPromise
} from './promise'
const HOOKS = [
'invoke',
'success',
'fail',
'complete',
'returnValue'
]
const globalInterceptors = {}
const scopedInterceptors = {}
function mergeHook (parentVal, childVal) {
const res = childVal
? parentVal
? parentVal.concat(childVal)
: Array.isArray(childVal)
? childVal : [childVal]
: parentVal
return res
? dedupeHooks(res)
: res
}
function dedupeHooks (hooks) {
const res = []
for (let i = 0; i < hooks.length; i++) {
if (res.indexOf(hooks[i]) === -1) {
res.push(hooks[i])
}
}
return res
}
function removeHook (hooks, hook) {
const index = hooks.indexOf(hook)
if (index !== -1) {
hooks.splice(index, 1)
}
}
function mergeInterceptorHook (interceptor, option) {
Object.keys(option).forEach(hook => {
if (HOOKS.indexOf(hook) !== -1 && isFn(option[hook])) {
interceptor[hook] = mergeHook(interceptor[hook], option[hook])
}
})
}
function removeInterceptorHook (interceptor, option) {
if (!interceptor || !option) {
return
}
Object.keys(option).forEach(hook => {
if (HOOKS.indexOf(hook) !== -1 && isFn(option[hook])) {
removeHook(interceptor[hook], option[hook])
}
})
}
export function addInterceptor (method, option) {
if (typeof method === 'string' && isPlainObject(option)) {
if (!shouldPromise(method)) {
return console.warn(`${method} 不支持设置拦截器`)
}
mergeInterceptorHook(scopedInterceptors[method] || (scopedInterceptors[method] = {}), option)
} else if (isPlainObject(method)) {
mergeInterceptorHook(globalInterceptors, method)
}
}
export function removeInterceptor (method, option) {
if (typeof method === 'string') {
if (isPlainObject(option)) {
removeInterceptorHook(scopedInterceptors[method], option)
} else {
delete scopedInterceptors[method]
}
} else if (isPlainObject(method)) {
removeInterceptorHook(globalInterceptors, method)
}
}
function wrapperHook (hook) {
return function (data) {
return hook(data) || data
}
}
function isPromise (obj) {
return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'
}
function queue (hooks, data) {
let promise = false
for (let i = 0; i < hooks.length; i++) {
const hook = hooks[i]
if (promise) {
promise = Promise.then(wrapperHook(hook))
} else {
const res = hook(data)
if (isPromise(res)) {
promise = Promise.resolve(res)
}
if (res === false) {
return {
then () {}
}
}
}
}
return promise || {
then (callback) {
return callback(data)
}
}
}
function wrapperOptions (interceptor, options = {}) {
['success', 'fail', 'complete'].forEach(name => {
if (Array.isArray(interceptor[name])) {
const oldCallback = options[name]
options[name] = function callbackInterceptor (res) {
queue(interceptor[name], res).then((res) => {
/* eslint-disable no-mixed-operators */
return isFn(oldCallback) && oldCallback(res) || res
})
}
}
})
return options
}
export function wrapperReturnValue (method, returnValue) {
const returnValueHooks = []
if (Array.isArray(globalInterceptors.returnValue)) {
returnValueHooks.push(...globalInterceptors.returnValue)
}
const interceptor = scopedInterceptors[method]
if (interceptor && Array.isArray(interceptor.returnValue)) {
returnValueHooks.push(...interceptor.returnValue)
}
returnValueHooks.forEach(hook => {
returnValue = hook(returnValue) || returnValue
})
return returnValue
}
function getApiInterceptorHooks (method) {
const interceptor = Object.create(null)
Object.keys(globalInterceptors).forEach(hook => {
if (hook !== 'returnValue') {
interceptor[hook] = globalInterceptors[hook].slice()
}
})
const scopedInterceptor = scopedInterceptors[method]
if (scopedInterceptor) {
Object.keys(scopedInterceptor).forEach(hook => {
if (hook !== 'returnValue') {
interceptor[hook] = (interceptor[hook] || []).concat(scopedInterceptor[hook])
}
})
}
return interceptor
}
export function invokeApi (method, api, options, ...params) {
const interceptor = getApiInterceptorHooks(method)
if (interceptor) {
if (Array.isArray(interceptor.invoke)) {
const res = queue(interceptor.invoke, options)
return res.then((options) => {
return api(wrapperOptions(interceptor, options), ...params)
})
} else {
return api(wrapperOptions(interceptor, options), ...params)
}
}
return api(options, ...params)
}
export const promiseInterceptor = {
returnValue (res) {
if (!isPromise(res)) {
return res
}
return res.then(res => {
return res[1]
}).catch(res => {
return res[0]
})
}
}
......@@ -2,7 +2,13 @@ import {
isFn
} from 'uni-shared'
const SYNC_API_RE = /^\$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/
import {
invokeApi,
wrapperReturnValue
} from './interceptor'
const SYNC_API_RE =
/^\$|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/
const CONTEXT_API_RE = /^create|Manager$/
......@@ -49,10 +55,10 @@ export function promisify (name, api) {
}
return function promiseApi (options = {}, ...params) {
if (isFn(options.success) || isFn(options.fail) || isFn(options.complete)) {
return api(options, ...params)
return wrapperReturnValue(name, invokeApi(name, api, options, ...params))
}
return handlePromise(new Promise((resolve, reject) => {
api(Object.assign({}, options, {
return wrapperReturnValue(name, handlePromise(new Promise((resolve, reject) => {
invokeApi(name, api, Object.assign({}, options, {
success: resolve,
fail: reject
}), ...params)
......@@ -68,6 +74,6 @@ export function promisify (name, api) {
)
}
}
}))
})))
}
}
}
import {
promiseInterceptor
} from 'uni-helpers/interceptor'
export {
addInterceptor,
removeInterceptor
}
from 'uni-helpers/interceptor'
export const interceptors = {
promiseInterceptor
}
import {
expect
} from 'chai'
describe('接口`addInterceptor`', () => {
it('同步拦截器 invoke', done => {
const setStorageInterceptor = {
invoke(args) {
args.data = 2
}
}
uni.addInterceptor('setStorage', setStorageInterceptor)
uni.setStorage({
key: 'test',
data: 1
}).then(function() {
expect(uni.getStorageSync('test')).eq(2)
uni.removeInterceptor('setStorage')
return uni.setStorage({
key: 'test',
data: 1
})
}).then(function() {
expect(uni.getStorageSync('test')).eq(1)
done()
})
})
it('同步拦截器 callback', done => {
const setStorageInterceptor = {
success(res) {
res.data = 2
},
complete(res) {
res.data = 3
}
}
uni.addInterceptor('setStorage', setStorageInterceptor)
uni.setStorage({
key: 'test',
data: 1,
success(res) {
expect(res.data).eq(2)
},
complete(res) {
uni.removeInterceptor('setStorage')
expect(res.data).eq(3)
done()
}
})
})
it('异步拦截器 invoke', done => {
const setStorageInterceptor = {
invoke(args) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
args.data = 2
resolve(args)
}, 200)
})
}
}
uni.addInterceptor('setStorage', setStorageInterceptor)
uni.setStorage({
key: 'test',
data: 1
}).then(function() {
expect(uni.getStorageSync('test')).eq(2)
uni.removeInterceptor('setStorage')
return uni.setStorage({
key: 'test',
data: 1
})
}).then(function() {
expect(uni.getStorageSync('test')).eq(1)
done()
})
})
it('异步拦截器 callback', done => {
const setStorageInterceptor = {
success(res) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
res.data = 2
resolve(res)
}, 200)
})
},
complete(res) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
res.data = 3
resolve(res)
}, 1000)
})
}
}
uni.addInterceptor('setStorage', setStorageInterceptor)
uni.setStorage({
key: 'test',
data: 1,
success(res) {
expect(res.data).eq(2)
},
complete(res) {
expect(res.data).eq(3)
uni.setStorage({
key: 'test',
data: 1
}).then(function(res) {
uni.removeInterceptor('setStorage')
expect(res[1].data).eq(2)
done()
})
}
})
})
it('全局拦截器 promiseInterceptor', done => {
uni.addInterceptor(uni.interceptors.promiseInterceptor)
uni.setStorageSync('test', 1)
uni.getStorage({
key: 'test'
}).then(res => {
expect(res.data).eq(1)
uni.removeInterceptor(uni.interceptors.promiseInterceptor)
uni.getStorage({
key: 'test'
}).then(res => {
expect(res[1].data).eq(1)
done()
})
})
})
})
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册