You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
function 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]);
}
XHR有一个 timeout 属性,使用该属性也可以简单实现超时功能,但是为了能支持多个XHR同时超时或者其他功能,我们采用了容易理解的异步方式在XHR中通过超时来实现取消正在进行中的操作。
让Promise等待指定时间
首先我们来看一下如何在Promise中实现超时。
所谓超时就是要在经过一定时间后进行某些操作,使用 setTimeout 的话很好理解。
首先我们来串讲一个单纯的在Promise中调用 setTimeout 的函数。
delayPromise.js
delayPromise(ms) 返回一个在经过了参数指定的毫秒数后进行onFulfilled操作的promise对象,这和直接使用 setTimeout 函数比较起来只是编码上略有不同,如下所示。
在这里 promise对象 这个概念非常重要,请切记。
Promise.race中的超时
让我们回顾一下静态方法 Promise.race ,它的作用是在任何一个promise对象进入到确定(解决)状态后就继续进行后续处理,如下面的例子所示。
我们可以将刚才的 delayPromise 和其它promise对象一起放到 Promise.race 中来是实现简单的超时机制。
simple-timeout-promise.js
函数 timeoutPromise(比较对象promise, ms) 接收两个参数,第一个是需要使用超时机制的promise对象,第二个参数是超时时间,它返回一个由 Promise.race 创建的相互竞争的promise对象。
之后我们就可以使用 timeoutPromise 编写下面这样的具有超时机制的代码了。
虽然在发生超时的时候抛出了异常,但是这样的话我们就不能区分这个异常到底是普通的错误还是超时错误了。
为了能区分这个 Error 对象的类型,我们再来定义一个Error 对象的子类 TimeoutError。
定制Error对象
Error 对象是ECMAScript的内建(build in)对象。
但是由于stack trace等原因我们不能完美的创建一个继承自 Error 的类,不过在这里我们的目的只是为了和Error有所区别,我们将创建一个 TimeoutError 类来实现我们的目的。
为了让我们的 TimeoutError 能支持类似 error instanceof TimeoutError 的使用方法,我们还需要进行如下工作。
TimeoutError.js
我们定义了 TimeoutError 类和构造函数,这个类继承了Error的prototype。
它的使用方法和普通的 Error 对象一样,使用 throw 语句即可,如下所示。
有了这个 TimeoutError 对象,我们就能很容易区分捕获的到底是因为超时而导致的错误,还是其他原因导致的Error对象了。
通过超时取消XHR操作
到这里,我想各位读者都已经对如何使用Promise来取消一个XHR请求都有一些思路了吧。
取消XHR操作本身的话并不难,只需要调用 XMLHttpRequest 对象的 abort() 方法就可以了。
为了能在外部调用 abort() 方法,我们先对之前本节出现的 getURL 进行简单的扩展,cancelableXHR 方法除了返回一个包装了XHR的promise对象之外,还返回了一个用于取消该XHR请求的_abort_方法。
delay-race-cancel.js
在这些问题都明了之后,剩下只需要进行Promise处理的流程进行编码即可。大体的流程就像下面这样。
和正常的promise一样,通过 then 返回请求结果
抛出 throw TimeoutError 异常并被 catch
catch的错误对象如果是 TimeoutError 类型的话,则调用 abort 方法取消XHR请求
将上面的步骤总结一下的话,代码如下所示。
delay-race-cancel-play.js
上面的代码就通过在一定的时间内变为解决状态的promise对象实现了超时处理。
promise和操作方法
在前面的 cancelableXHR 中,promise对象及其操作方法都是在一个对象中返回的,看起来稍微有些不太好理解。
从代码组织的角度来说一个函数只返回一个值(promise对象)是一个非常好的习惯,但是由于在外面不能访问 cancelableXHR 方法中创建的 req 变量,所以我们需要编写一个专门的函数(上面的例子中的_abort_)来对这些内部对象进行处理。
当然也可以考虑到对返回的promise对象进行扩展,使其支持_abort_方法,但是由于promise对象是对值进行抽象化的对象,如果不加限制的增加操作用的方法的话,会使整体变得非常复杂。
大家都知道一个函数做太多的工作都不认为是一个好的习惯,因此我们不会让一个函数完成所有功能,也许像下面这样对函数进行分割是一个不错的选择。
将这些处理整理为一个模块的话,以后扩展起来也方便,一个函数所做的工作也会比较精炼,代码也会更容易阅读和维护。
我们有很多方法来创建一个模块(AMD,CommonJS,ES6 module etc..),在这里,我们将会把前面的 cancelableXHR 整理为一个Node.js的模块使用。
cancelableXHR.js
使用方法也非常简单,我们通过 createXHRPromise 方法得到XHR的promise对象,当想对这个XHR进行_abort_ 操作的时候,将这个promise对象传递给 abortPromise(promise) 方法就可以了。
总结
在这里我们学到了如下内容。
Promise能非常灵活的进行处理流程的控制,为了充分发挥它的能力,我们需要注意不要将一个函数写的过于庞大冗长,而是应该将其分割成更小更简单的处理,并对之前JavaScript中提到的机制进行更深入的了解。
原文
The text was updated successfully, but these errors were encountered: