Предотвращение множественных вызовов axios

Я использую axios в своем приложении VueJS. На данный момент в каждом компоненте я использую переменную в каждом компоненте, чтобы проверить, нажал ли пользователь кнопку перед запуском вызова axios. Это приводит к большому количеству повторяющегося кода, поэтому я подумал о переносе вызовов axios в функцию "uniqueAxios", например:

const urlsAPI = [];
const uniqueAxios = async (method, url, data) => {
  if (urlsAPI.includes(url)) {
    console.info('Already called!!');
    Promise.reject(new Error('Already called'));
  } else {
    urlsAPI.push(url);
    await axios[method](url, data)
      .then((res) => {
        console.info('OK');
        console.info(res);
        return Promise.resolve(res);
      })
      .catch((e) => {
        console.info('KO');
        console.info(e);
        return Promise.reject(e);
      });
  }
};

Но когда я использую эту функцию в своем компоненте, вот так:

await uniqueAxios(
          'post',
          `${process.env.VUE_APP_API_URL}/XXX`,
        )
          .then((res) => {
            console.info(res);
          })
          .catch((e) => {
            console.info(e);

Консоль выдает ошибку: TypeError: res is undefined. Однако с API связываются. Просто я не могу справиться с then и catch, которые у меня были раньше, когда я напрямую использовал axios.

Я уверен, что функция упаковки uniqueAxios неверна. Кто-нибудь знает, как мне с этим справиться? Заранее спасибо.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
65
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

У вас несколько проблем, во-первых, вы ничего не возвращаете в своей функции.

const uniqueAxios = async (method, url, data) => {
  if (urlsAPI.includes(url)) {
    console.info('Already called!!');
    Promise.reject(new Error('Already called'));
  } else {
    urlsAPI.push(url);
    return await axios[method](url, data) // You need to return the axios
      .then((res) => {
        console.info('OK');
        console.info(res);
        return Promise.resolve(res); // This line return inside the promise axios not the function
      })
      .catch((e) => {
        console.info('KO');
        console.info(e);
        return Promise.reject(e);
      });
  }
};

Во-вторых, вы ждете и ничего не делаете. Теперь с этим изменением вы можете ожидать свою функцию, как это, и регистрировать ответ.

const response = await uniqueAxios(
  'post',
  `${process.env.VUE_APP_API_URL}/XXX`,
  )
console.info(response)

Спасибо, Рафаэль, мне удалось решить мою проблему, и я опубликовал ответ. Вы можете пересмотреть его, если хотите.

djcaesar9114 14.10.2022 14:31

Да, вы делаете то же самое, что и второй блок. Это лучше всего, сохраните ответ внутри константы и сделайте что-нибудь с ним;) Но поймите, может быть, в другой раз, когда вы возвращаете блок, подобный ir then, это возвращает внутри обещания, а не начального оператора блока (то же самое с map, filter . ...).

Raphael Rlt 14.10.2022 14:41

[EDIT: это работает, но ответ, который я выбрал, намного лучше]

На самом деле я нашел решение:

let urlsAPI = [];
const uniqueAxios = async (method, url, data) => {
  if (urlsAPI.includes(url)) {
    throw new Error('Axios already called');
  }
  urlsAPI.push(url);
  const t = {
    type: 0,
    content: null,
  };
  await axios[method](url, data)
    .then((res) => {
      t.content = res;
      t.type = 1;
    })
    .catch((e) => {
      t.content = e;
    })
    .finally(() => {
      urlsAPI = urlsAPI.filter((u) => u !== url);
    });
  if (t.type) {
    return t.content;
  }
  throw t.content;
};
Ответ принят как подходящий

Ваш исходный код

const urlsAPI = [];

const uniqueAxios = async (method, url, data) => {
  if (urlsAPI.includes(url)) {
    console.info('Already called!!');
    Promise.reject(new Error('Already called'));
  } else {
    urlsAPI.push(url);
    await axios[method](url, data)
      .then((res) => {
        console.info('OK');
        console.info(res);
        return Promise.resolve(res);
      })
      .catch((e) => {
        console.info('KO');
        console.info(e);
        return Promise.reject(e);
      });
  }
};

Все функции async возвращают обещание, даже что-то вроде:

async function three() {
  return 3;
}

или это

async function belch() {
  throw new Error("Belch!");
}

который будет разрешаться или отклоняться в зависимости от того, была ли выдана ошибка.

Поскольку вы явно не возвращаете значение, возвращаемое значение представляет собой обещание, которое разрешается как undefined (если не выдается ошибка, в этом случае оно отклоняется).

Ваш код был бы чище (и работал!), если бы вы просто сказали что-то вроде этого:

const inFlightUrls = new Set();

const uniqueAxios = async (method, url, data) => {

  const inflight = inFlightUrls.has(url);
  if (inFlight) {
    throw new Error('Already called');
  }

  inFlightUrls.add(url);

  const res = axios[method](url, data)
              .finally( () => inflightUrls.delete(url) ) ;

  return res ;
};

Приведенная выше функция возвращает обещание, которое либо разрешается с помощью объекта ответа Axios, либо отклоняется с ошибкой (либо от Axios, либо от вас).

Большое спасибо за ваш ответ. Что вы думаете об ответе, который я опубликовал после прочтения ответа Рафаэля? Мне нужен ваш опыт в этом. Это работает для меня в моем приложении, но я, возможно, написал неправильный код.

djcaesar9114 18.10.2022 08:06

Вероятно, это работает, но это ужасно сложно. Весь смысл async/await в том, что это синтаксический сахар, который избавляет от всех обратных вызовов и дает вам более простой процедурный код.

Nicholas Carey 18.10.2022 20:09

Я попробовал ваш ответ, он работает как шарм, и Set - действительно хорошая идея ... Я проголосовал за него вместо своего, спасибо.

djcaesar9114 19.10.2022 13:25

Другие вопросы по теме