这是一个前端简易版接口聚合模块,主要用于如下场景:前端
避免发起相同的请求,某些状况下发起了相同的请求,经收集处理后,实际只发起一个请求。可是不一样的发起端的callback 都能获得处理。webpack
调用方法:requestCombo()
参数:ios
apiData: ApiData, params: object, callback: Function, request = axios, collectTime = 100, isCombo = true, errorHandle?: Function
ApiData 类型中包含如下内容:git
import axios from 'axios'; interface ApiData { url: string; pack: Function; unpack: Function; maxComboNum?: number; requestMethod?: string; } /** * status: number * 0:init * 1:pending * 2:done * * request * The api must be the same as axios */ const dataCache: object = {}; const busData: object = {}; export const requestCombo = (apiData: ApiData, params: object, callback?: Function, request = axios, collectTime = 100, isCombo = true, errorHandle?: Function) => { const { url, requestMethod = 'get', maxComboNum = 10, pack, unpack } = apiData; const method: string = requestMethod.toLocaleLowerCase(); const cacheKey = `${url}_${method}_${JSON.stringify(params)}`; const busKey = `${url}_${method}`; if (!url) return; const sendRequest = async () => { clearTimeout(busData[busKey].timer); const paramList = busData[busKey].paramList; const paramObject = pack(paramList); busData[busKey] = null; try { const result = await applyRequest(url, paramObject, method, request); // 拆解,拆完要对应回去,所以要用 param 作key const obj = unpack(result, paramList) || {}; Object.keys(obj).forEach((key) => { const dataNode = dataCache[cacheKey]; if (!dataNode) { errorHandle ? errorHandle('Data Unpack Error') : console.log('Data Unpack Error'); } else { dataNode.data = obj[key]; dataNode.status = 2; dataNode.cbs.forEach((cb: Function) => { cb(obj[key]); }); } }); } catch (ex) { if (errorHandle) { errorHandle(ex); return; } throw ex; } }; return new Promise((resolve, reject) => { if (!callback) callback = () => { }; //预处理接口返回数据 const _callback = callback; callback = (json: any) => { const raw = _callback(json); if (raw && typeof raw.then === 'function') {//认为是Promise raw.then((data: any) => { resolve(data); }).catch((err: any) => { reject(err); }); //终结的promise链必须捕获错误,不然丢失错误链 } else { resolve(raw); } }; if (dataCache[cacheKey]) { if (dataCache[cacheKey].status === 1) { dataCache[cacheKey].cbs.push(callback); } else if (dataCache[cacheKey].status === 2) { callback(dataCache[cacheKey].data); } } else { dataCache[cacheKey] = { status: 1, cbs: [], data: {} }; if (!isCombo) { applyRequest(url, params, requestMethod, request).then((data: object) => { dataCache[cacheKey].status = 2; dataCache[cacheKey].data = data; dataCache[cacheKey].cbs.forEach((cb: Function) => { cb(data); }); resolve(data); }); } else { if (!busData[busKey]) { busData[busKey] = { paramList: [params], url, timer: setTimeout(sendRequest, collectTime) }; } else { busData[busKey].paramList.push(params); // 加入参数队列 if (busData[busKey].paramList.length >= maxComboNum) { // 发起请求 sendRequest(); } } } } }).catch((ex) => { if (errorHandle) { errorHandle(ex); return; } throw ex; }); }; const applyRequest = async (url: string, params: object, requestMethod = 'get', request: any, ) => { if (requestMethod === 'get') { return request[requestMethod](url, { params }); } else { return request[requestMethod](url, { ...params }); } };
详见:https://github.com/LuckyWinty/ToolLibrary/tree/master/src/RequestCombogithub
const ApiData = { getPrice: { url: '//test/prices', maxComboNum: 10, requestMethod: 'get', pack (paramList: object[]) { const skuids: string[] = []; paramList.forEach((p: any) => { if (p.skuids) { skuids.push(p.skuids); } }); const ret = { skuids: skuids.join(',') }; console.log('合并后的价格参数', ret); return ret; }, unpack: (data: any, paramList: object[]) => { if (data && data.data && length) { const resData = data.data || []; const ret = {}; paramList.forEach((p: any) => { const key = JSON.stringify(p); resData.some((item: any, i: number) => { const sku = item.sku; if (sku === p.skuids) { ret[key] = [data[i]]; return true; } return false; }); }); console.log('价格拆解数据', ret); return ret; } return []; } } }; const p1 = requestCombo(ApiData['getPrice'], { skuids: '11111' }, (data: any) => { console.log(data); }); const p2 = requestCombo(ApiData['getPrice'], { skuids: '11112' }, (data: any) => { console.log(data); }); const p3 = requestCombo(ApiData['getPrice'], { skuids: '11113' }, (data: any) => { console.log(data); }); const data1 = await p1; const data2 = await p2; const data3 = await p3;
这种状况适合使用 webpack 来做为打包器。咱们主要配置几个点:web
//webpack.config.js const TerserPlugin = require('terser-webpack-plugin'); module.exports = { entry: { 'RequestCombo': './src/index.js', 'RequestCombo.min': './src/index.js' }, output: { filename: '[name].js', library: 'RequestCombo', libraryTarget: 'umd', libraryExport: 'default' }, mode: 'none', optimization: { minimize: true, minimizer: [ new TerserPlugin({ include: /\.min\.js$/, }) ] } }
这个跟 webpack 打包的目标是一致的。就是工具不一样,配置稍有差别.npm
//为展现方便,删除了部分插件 const filesize = require('rollup-plugin-filesize') const path = require('path') const { terser } = require('rollup-plugin-terser') const { name, version, author } = require('../package.json') const componentName = process.env.COMPONENT const componentType = process.env.COMPONENT_TYPE || 'js' const banner = `${'/*!\n* '}${name}.js v${version}\n` + ` * (c) 2018-${new Date().getFullYear()} ${author}\n` + ' * Released under the MIT License.\n' + ' */' module.exports = [ { input: path.resolve(__dirname, `../src/${componentName}/src/index.${componentType}`), output: [ { file: path.resolve( __dirname, `../src/${componentName}/dist/${componentName}.min.js` ), format: 'umd', name, banner, sourcemap: true, } ], plugins: [terser(), filesize()], }, { input: path.resolve(__dirname, `../src/${componentName}/src/index.${componentType}`), output: { file: path.resolve( __dirname, `../src/${componentName}/dist/${componentName}.min.esm.js` ), format: 'esm', banner, }, plugins: [terser(), filesize()], }, { input: path.resolve(__dirname, `../src/${componentName}/src/index.${componentType}`), output: [ { file: path.resolve( __dirname, `../src/${componentName}/dist/${componentName}.js` ), format: 'umd', name, banner, } ], plugins: [], } ]
详见:https://github.com/LuckyWinty/ToolLibraryjson
添加用户: npm adduseraxios
登录: npm loginapi
发布版本: npm publish
升级版本:
升级大版本号: npm version major