【问题标题】:axios abort all request when one failsaxios 在一个失败时中止所有请求
【发布时间】:2021-10-03 05:09:07
【问题描述】:

我有一行多个待处理的请求

const requests = [];

requests.push(axios.post('/request1', {moo:1});
requests.push(axios.post('/request2', {moo:2});
requests.push(axios.post('/request3', {moo:3});

Promise.all(requests).then((reponse) => {
    debugger;
}).catch((err) => {
    debugger;
});

如果其中一个失败,我会尝试中止所有。 不幸的是,目前如果失败,仍然会发出下一个请求。

我尝试了一些取消代码,但下一个请求仍然触发

const requests = [];
const source = axios.CancelToken.source();
const cancelToken = source.token;

requests.push(axios.post('/request1', {moo:1}, {cancelToken} );
requests.push(axios.post('/request2', {moo:2}, {cancelToken} );
requests.push(axios.post('/request3', {moo:3}, {cancelToken} );

Promise.all(requests).then((reponse) => {
    debugger;
}).catch((err) => {
    source.cancel("Request canceled");
    debugger;
});

【问题讨论】:

  • "...但是下一个请求仍然触发..."“仍然触发”是什么意思?
  • @T.J.Crowder 它仍在执行并且请求到达服务器

标签: javascript ajax promise axios cancellation


【解决方案1】:

使用自定义库,您可以执行以下操作 (Live Demo):

import { CPromise } from "c-promise2";
import CPAxios from "cp-axios";

(async (urls) => {
  try {
    const responses = await CPromise.all(
      function* () {
        for (const url of urls) {
          yield CPAxios(url);
        }
      },
      { concurrency: 3 } // optionally
    );
    console.log(responses);
  } catch (err) {
    console.warn(`Fail: ${err}`);
  }
})([
  "https://rickandmortyapi.com/api/character/1",
  "https://rickandmortyapi.com/api/character/2",
  "https://rickandmortyapi.com/api/character/3",
  "https://rickandmortyapi.com/api/character/4",
  "https://rickandmortyapi.com/api/character/5",
  "https://rickandmortyapi.com/api/character/BadID",
  "https://rickandmortyapi.com/api/character/7",
  "https://rickandmortyapi.com/api/character/8"
]);

或使用映射器功能(Live Demo):

import { CPromise } from "c-promise2";
import CPAxios from "cp-axios";

(async (urls) => {
  try {
    const responses = await CPromise.all(urls, {
      mapper(url) {
        return CPAxios(url);
      },
      concurrency: 3
    });
    console.log(responses);
  } catch (err) {
    console.warn(`Fail: ${err}`);
  }
})([
  "https://rickandmortyapi.com/api/character/1",
  "https://rickandmortyapi.com/api/character/2",
  "https://rickandmortyapi.com/api/character/3",
  "https://rickandmortyapi.com/api/character/4",
  "https://rickandmortyapi.com/api/character/5",
  "https://rickandmortyapi.com/api/character/BadID",
  "https://rickandmortyapi.com/api/character/7",
  "https://rickandmortyapi.com/api/character/8"
]);

【讨论】:

    【解决方案2】:

    我尝试了一些取消代码,但下一个请求仍然触发

    您在此处开始请求(如果我假设每行都有一个结束 )):

    requests.push(axios.post('/request1', {moo:1}, {cancelToken} ));
    requests.push(axios.post('/request2', {moo:2}, {cancelToken} ));
    requests.push(axios.post('/request3', {moo:3}, {cancelToken} ));
    

    此时,请求正在进行中。 Promise.all运行任何东西,它观察已经运行的东西。

    当您在Promise.all 的承诺上的拒绝处理程序运行时,您使用取消令牌的代码将在可能的情况下取消请求,但除非您连续运行您的请求(一次一个),否则它们都会开始在那之前。

    如果你想串联起来,最简单的方法是使用async 函数:

    async function postInSeries(iterable) {
        // Does the requests in series
        const results = [];
        for (const request of iterable) {
            results.push(await axios.post(...request));
        }
        return results;
    }
    // ...
    postInSeries([
        ['/request1', {moo:1}],
        ['/request2', {moo:2}],
        ['/request3', {moo:3}],
    ])
    .then(results => {
        // ...use the results...
    })
    .catch(error => {
        // ...handle/report error...
    });
    

    【讨论】:

    • 我还能以某种方式中止它们吗?或者如果这不可能,我应该使用什么模式来控制流产?
    • @BatMan - 这就是取消令牌的作用,它会在可能的情况下取消正在进行的请求。但是当然,一旦它到达服务器,它就到达了服务器,你所做的就是取消处理响应。 (也可能关闭连接,服务器可能会或可能不会看到并能够使用它来停止工作。)
    猜你喜欢
    • 2020-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-03
    • 2020-06-06
    • 1970-01-01
    • 2019-02-25
    • 1970-01-01
    相关资源
    最近更新 更多