這是一個前端簡易版接口聚合模塊,主要用於如下場景:前端
避免發起相同的請求,某些狀況下發起了相同的請求,經收集處理後,實際只發起一個請求。可是不一樣的發起端的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