Promise.race 实现fetch超时封装
race是Promise的方法之一,使用场景是,众多请求发出之后,只要有一个请求【成功 | 失败】,就会触发 【then | catch】方法。其它的请求再返回也无用了,
这块区别于Promise.all,Promise.all使用场景是全部请求成功之后才会触发then方法,有一个请求失败就有触发catch方法。
用法如下:
Promise.race([ new Promise((resolve, reject) => { //永远会执行这个方法 setTimeout(() => { resolve(`我先成功了`) }, 100) }), new Promise((resolve, reject) => { //这个方法也会执行但是对后面数据没有任何作用 setTimeout(() => { resolve(`我也成功了,但是并没有什么用了!`) }, 400) }) ]) //data永远是 "我先成功了" .then((data) => { console.log(`then data: ${data}`); return data }) .catch((e) => { console.log(`catch data: ${e}`); return e; }) .finally(() => { console.log(`finally !!!`); })
利用“赛跑机制”,可以实现ajax的超时功能
/** * fetch的封装, 返回promise * @param {string} url - 请求地址 * @param {method} [method] - 请求方式 * @param {object} [data] - 请求参数 * @param {number} [timeout] - 超时时间ms * @returns {promise} */ // fetch polyfill import 'whatwg-fetch'; export interface AjaxParams { /** * 请求地址url */ url: string; /** * 请求方式,默认GET */ method?: 'GET' | 'POST' | 'OPTION' | 'HEAD'; /** * 请求参数,object格式 */ data?: any; /** * 超时时间,单位ms,默认10*1000ms(10秒) */ timeout?: number; } const Ajax = ({ method = 'GET', url, data, timeout = 10 * 1000 }: AjaxParams): Promise<any> => { const fetchParams = { method: method || 'GET', headers: [ ['Accept', 'application/json, text/javascript, */*; q=0.01'], ['Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'], ], }; // enable cookie fetchParams['credentials'] = 'include'; // 跨域 // fetchParams['mode'] = 'cors'; // 将data拿出来, get放到url里面, post放到body里面 let body = ''; if (data && method !== 'GET' && method !== 'HEAD') { for (const p in data) { body += `${p}=${encodeURIComponent(data[p])}&`; } body = body.substring(0, body.length - 1); fetchParams['body'] = body; } if (data && method === 'GET') { let urlPayload = '?'; for (const p in data) { urlPayload += `${p}=${encodeURIComponent(data[p])}&`; } urlPayload = urlPayload.substring(0, urlPayload.length - 1); url += urlPayload; } // setTimeout Promise, fetch是不会abort和超时的, 自己实现一个超时reject功能 const timeoutPromise = new Promise((resolve, reject) => { setTimeout(() => { reject(new Error('request timeout')); }, timeout); }); const fetchPromise = new Promise((resolve, reject) => { fetch(url, fetchParams).then((response) => { if (response.status !== 200) { reject(new Error(`Response Error: ${response.status}`)); } response.json().then((responseJson) => { const resultCode = parseInt(responseJson.resultCode); resolve(responseJson); }).catch((error) => { reject(error); }); }).catch((error) => { reject(error); }); }); // 用race实现timeout功能 return Promise.race([timeoutPromise, fetchPromise]); }; export default Ajax;
这样的好处是把正常的异步请求封装与超时代码分离了。