连续同源异步操做队列

问题的发现

来自同源的多个异步操做可能引发异步冲突问题,特别是在网络请求时。同源操做产生了两个ajax请求,它们的请求结果将用于渲染同一个区域,然而因为网络问题,先发出的请求后返回,致使最终获得的界面是错误的。html

解决这个问题的最好办法,是利用原生XHR的abort方法,在后一次操做时,将前一次操做引发的ajax请求给cancel掉。ios

可是在现实条件下,异步操做并不是都有cancel操做。js原生的Promise没有,原生的fetch基于Promise也没有。基于Promise的不少工具都没有cancel操做。这种状况下怎么解决这个问题呢?git

其实方法是有的,就是直接丢弃Promise的推送,不执行它的resolve回调便可。这样,虽然异步操做已经执行了,但不会对现有的环境形成任何反作用。(虽然这样看上去浪费了异步操做这个资源。)github

问题的思考

如何来判断是否要丢掉它的回调?咱们能够建立一个队列,每次产生一个异步操做时,就将它加入到队列中,当队列中存在操做对象时,每次只取最后一个,等待它推送结果,执行它的回调,排在它前面的操做所有丢弃掉。ajax

基于这样的想法,我写了一个工具。它为异步操做建立队列,并根据不一样的场景实现不一样的队列操做形式。你能够经过这里阅读它的源码和文档。它提供了4种可供选择的场景,开发者根据本身的实际场景选择使用其中的一种。npm

问题的解决

基于上述的思考,我最终发布了deferer-queue,你能够经过npm安装这个包,在本身的项目中使用它。它的操做模式超级简单,首先实例化一个queue对象,而后往这个queue push异步操做,异步操做被装在一个函数中被push进队列,它的回调函数必定是按照push的顺序执行。axios

import DefererQueue from 'deferer-queue'

const queue = new DefererQueue()

const defer1 = () => new Promise((resolve, reject) => { ... })
const defer2 = () => axios.get(...)
const defer3 = async () => ...

queue.push(defer1).then(() => { console.log(1) })
queue.push(defer2).then(() => { console.log(2) })
queue.push(defer3).then(() => { console.log(3) })复制代码

不管defer1-3中的谁,执行后谁先返回结果,控制台输出的结果永远是1 2 3(defer都成功的前提下),由于deferer-queue设计的就是保证回调是按push顺序执行。bash

要使用不一样模式,只须要在实例化的时候,传入一个options对象,将mode设置为parallel/serial/switch/shift中的一个便可:网络

const queue = new DefererQueue({
  mode: 'switch',
})复制代码

其余的用法同样。这样,你的队列就会只采用最后一个push进队列的defer的结果,即便你的队列正在进行,只要有新的defer被push进去,那以前的全部操做都会被丢掉,队列运行结果只取最后一个操做的结果。异步

关于具体的API使用细则,你能够阅读它的文档。其中,利用axios的cancel能力那个地方很是有借鉴意义。

关于四种运行模式的详细解释,因为图片限制,请到个人博客进行阅读。

相关文章
相关标签/搜索