咱们来看一下如何应用Promise.race来实现超时机制。
当然XHR有一个 timeout 属性,应用该属性也能够简略实现超时性能,然而为了能反对多个XHR同时超时或者其余性能,咱们采纳了容易了解的异步形式在XHR中通过超时来实现勾销正在进行中的操作。

让Promise期待指定工夫

首先咱们来看一下如何在Promise中实现超时。
所谓超时就是要在通过肯定工夫后进行某些操作,应用 setTimeout 的话很好了解。
首先咱们来串讲一个单纯的在Promise中调用 setTimeout 的函数。

//delayPromise.jsfunction delayPromise(ms) {    return new Promise(function (resolve) {        setTimeout(resolve, ms);    });}

Promise.race中的超时

Promise.race就是一组promise中只有有一个返回,其它的promise就不会执行后续回调(无论谬误还是胜利)

var winnerPromise = new Promise(function (resolve) {        setTimeout(function () {            console.log('this is winner');            resolve('this is winner');        }, 4);    });var loserPromise = new Promise(function (resolve) {        setTimeout(function () {            console.log('this is loser');            resolve('this is loser');        }, 1000);    });// 第一个promise变为resolve后程序进行,第二个promise不会进入回调Promise.race([winnerPromise, loserPromise]).then(function (value) {    console.log(value);    // => 'this is winner'});

咱们能够将方才的 delayPromise 和其它promise对象一起放到 Promise.race 中来是实现简略的超时机制。

//simple-timeout-promise.jsfunction delayPromise(ms) {    return new Promise(function (resolve) {        setTimeout(resolve, ms);    });}function timeoutPromise(promise, ms) {    var timeout = delayPromise(ms).then(function () {            throw new Error('Operation timed out after ' + ms + ' ms');        });    return Promise.race([promise, timeout]);//返回taskPromise和timeoutPromise组成的Promise.race}

定制TimeoutError对象

//TimeoutErrorclass TimeoutError extends Error{  constructor(msg){    super(msg)  }}

实例

class TimeoutError extends Error{  constructor(msg){    super(msg)  }}function delayPromise(ms) {    return new Promise(function (resolve) {        setTimeout(resolve, ms);    });}function timeoutPromise(promise, ms) {    var timeout = delayPromise(ms).then(function () {            throw new TimeOutError('Operation timed out after ' + ms + ' ms');        });    return Promise.race([promise, timeout]);}// 运行示例var taskPromise = new Promise(function(resolve){    // 轻易一些什么解决    var delay = Math.random() * 2000;    setTimeout(function(){        resolve(delay + "ms");    }, delay);});timeoutPromise(taskPromise, 1000).then(function(value){    console.log("taskPromise在规定工夫内完结 : " + value);}).catch(function(error){    if(error instance of TimeoutError){         console.log("产生超时", error);    }   });

通过超时勾销XHR操作

到这里,我想各位读者都曾经对如何应用Promise来勾销一个XHR申请都有一些思路了吧。

勾销XHR操作自身的话并不难,只须要调用 XMLHttpRequest 对象的 abort() 办法就能够了。

为了能在内部调用 abort() 办法,咱们先对之前本节呈现的 getURL 进行简略的扩大,cancelableXHR 办法除了返回一个包装了XHR的promise对象之外,还返回了一个用于勾销该XHR申请的abort办法。

//delay-race-cancel.jsfunction cancelableXHR(URL) {    var req = new XMLHttpRequest();    var promise = new Promise(function (resolve, reject) {            req.open('GET', URL, true);            req.onload = function () {                if (req.status === 200) {                    resolve(req.responseText);                } else {                    reject(new Error(req.statusText));                }            };            req.onerror = function () {                reject(new Error(req.statusText));            };            req.onabort = function () {                reject(new Error('abort this request'));            };            req.send();        });    var abort = function () {        // 如果request还没有完结的话就执行abort        // https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest        if (req.readyState !== XMLHttpRequest.UNSENT) {            req.abort();        }    };    return {        promise: promise,        abort: abort    };}

在这些问题都明了之后,剩下只须要进行Promise解决的流程进行编码即可。大体的流程就像上面这样。

通过 cancelableXHR 办法获得包装了XHR的promise对象和勾销该XHR申请的办法

在 timeoutPromise 办法中通过 Promise.race 让XHR的包装promise和超时用promise进行竞争。

XHR在超时前返回后果的话

和失常的promise一样,通过 then 返回申请后果
产生超时的时候

抛出 throw TimeoutError 异样并被 catch

catch的谬误对象如果是 TimeoutError 类型的话,则调用 abort 办法勾销XHR申请

将下面的步骤总结一下的话,代码如下所示。

//delay-race-cancel-play.jsclass TimeoutError extends Error{  constructor(msg){    super(msg)  }}function delayPromise(ms) {    return new Promise(function (resolve) {        setTimeout(resolve, ms);    });}function timeoutPromise(promise, ms) {    var timeout = delayPromise(ms).then(function () {            return Promise.reject(new TimeoutError('Operation timed out after ' + ms + ' ms'));        });    return Promise.race([promise, timeout]);}function cancelableXHR(URL) {    var req = new XMLHttpRequest();    var promise = new Promise(function (resolve, reject) {            req.open('GET', URL, true);            req.onload = function () {                if (req.status === 200) {                    resolve(req.responseText);                } else {                    reject(new Error(req.statusText));                }            };            req.onerror = function () {                reject(new Error(req.statusText));            };            req.onabort = function () {                reject(new Error('abort this request'));            };            req.send();        });    var abort = function () {        // 如果request还没有完结的话就执行abort        // https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest        if (req.readyState !== XMLHttpRequest.UNSENT) {            req.abort();        }    };    return {        promise: promise,        abort: abort    };}var object = cancelableXHR('http://httpbin.org/get');// maintimeoutPromise(object.promise, 1000).then(function (contents) {    console.log('Contents', contents);}).catch(function (error) {    if (error instanceof TimeoutError) {        object.abort();        return console.log(error);    }    console.log('XHR Error :', error);});

下面的代码就通过在肯定的工夫内变为解决状态的promise对象实现了超时解决。