🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
#### 1、实现方法 ```javascript /** * 向指定api循环发送发送请求 * @param {string} apiName api名称 * @param {object=} data 请求参数(可选) * @param {Function} cb 处理响应数据的回调 * @param {number=} interval 轮询间隔(毫秒)(可选,默认为配置值) * @return {Object} 用于对轮询状态进行操作的实例 */ export function fetchInterval(apiName, data, cb, emit, interval) { const argumentsLength = arguments.length const defaultInterval = config.get('fetchInterval') if(argumentsLength === 2) { // 只传了2个参数 // 没传data,没传interval cb = data data = null interval = null } else if(argumentsLength === 3) { // 只传了3个参数 if(isFunction(cb)) { // 没有传interval interval = null } else if(isNumber(cb)) { // 没有传data interval = cb cb = data data = null } } data = data || {} interval = interval || defaultInterval let hasClosed = false const delayFetchInterval = delay( function() { if(hasClosed) { return } fetch(apiName, data, cb).then(res => { emit(res) delayFetchInterval() }) // fetch(apiName, data, cb) // .always(delayFetchInterval) }, interval ) delayFetchInterval(true) return { // 停止轮询 close() { hasClosed = true } } } /** * 创建channel对象 * @param {string} apiName api名称 * @param {Object=} data 请求参数(可选) * @param {Function} cb 处理推送数据的回调 * @return {Function} websocket连接断开时需要执行的函数 */ function* createEventChannel(apiName, data, cb) { return eventChannel(emit => { if(config.get('mock')){ fetchInterval(apiName, data, cb, emit) return () => {} }else{ const ws = new ReconnectingWebSocket( apis.url(apiName, data) ) ws.onmessage= (message) => emit({data: JSON.parse(message.data)}) return () => { // ws.close(); }; } }); } /** * 实例化Channel对象,并监听回调函数,根据回调分发action * @param {string} apiName api名称 * @param {Object=} data 请求参数(可选) * @param {Function} cb 处理推送数据的回调 * @return {void} */ export function fetchSocket(apiName, data, cb){ return function* (createAction) { const channel = yield call(createEventChannel, apiName, data, cb); while(true){ const res = yield take(channel); yield put(createAction(res.data.result)) } } } ``` #### 2、代码说明 > 2.1 `fetchSocket`方法首先调用`createEventChannel`方法生成`Channel`对象,`createEventChannel`内部调用`redux-saga`提供的`eventChannel`方法,此方法提供一个带`emit`参数的回调函数,`emit`用于通知外部组件此函数执行结束并返回的结果,类似于`Promise`的`resolve`方法。所以,在`eventChannel`的回调函数里可以执行任何异步操作,在异步操作的回调函数里调用`emit()`方法,把结果作为参数返回即可。 > 2.2 `createEventChannel`成功返回了`Channel`对象,`const res = yield take(channel)`此段代码用于监听`emit`方法何时被触发,`res`便是从`emit`方法带回来的数据。 > 2.3 mock状态下,需要用`feterInterval`模拟socket,因此`feterInterval`方法中需要传入`emit`方法,以便于在每次`fetch`成功后可以触发`emit`成功返回数据。 #### 3、使用方法 `fetchSocket`是个高阶函数,调用时第一层跟往常一样,传入接口名称、参数、回调函数。第二层则传入生成`action`的方法。如下: ```javascript const apifetchMenu = (workTableMenuSuccess) => { return fetchSocket('fetchWorkTableLeftMenu')(workTableMenuSuccess) } /** * 监听WORK_TABLE_MENU_REQUEST,调用对应API方法,请求数据 * @param {object} action 工作台左边导航的action对象 */ export function* fetchWorkTableMenu() { try { yield take(WORK_TABLE_MENU_REQUEST) yield call(apifetchMenu, workTableMenuSuccess) } catch (error) { yield put(requestFailed(error.message)) } } ```