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;

这样的好处是把正常的异步请求封装与超时代码分离了。

 

 

 

 

posted on 2019-07-01 16:17  KyleLjc  阅读(1310)  评论(0编辑  收藏  举报

导航