Как элегантно управлять отображением глобальной загрузки?

внешний интерфейс axios

Во многих фоновых системах управления при отправке запроса нужно открыть загрузку, а после получения ответа загрузку закрыть.Для этой общей логики я обычно делаю эту обработку в перехватчике axios, т.к. каждый раз Каждый запрос должен отображать загрузку глобально, поэтому я добавил флаг showLoading в конфиг axios, чтобы отметить, нужно ли отображать загрузку перед отправкой запроса.После получения ответа определяется, нужно ли закрывать загрузку в соответствии с этой отметкой В перехватчике axios код выглядит следующим образом:


axios.interceptors.request.use(
  (config) => {
    // config中不设置showLoading这个字段或者这个字段为true时,代表需要全局显示loading
    if (config.headers.showLoading !== false) {
      // 全局显示loading
      Loading.showLoading();
    }
    return config;
  },
  (err) => {
    return Promise.reject(err);
  },
);

instance.interceptors.response.use(
  (response) => {
    const { config: { headers } } = response;
    if (headers.showLoading !== false) {
      // 关闭全局的loading
      Loading.hideLoading();
    }
    return data;
  }
);

Я, естественно, чувствую, что приведенная выше реализация естественным образом соответствует требованиям, но я иногда болтал с моими коллегами по бэкэнду об этой проблеме. сервера, а также сказал, что если бы Он был тем, кто состыковался со мной, то мне никогда не позволили бы этого сделать. Тогда я был ошеломлен, потому что я не мог придумать решение.

До моделей лука, фактически запросив, реагирует на естественные применимые модели лука, если модель лука добавляется к Axios, эта проблема естественным образом решит ее. Позвольте мне объяснить, как добавить модели лука в Axio, если есть модель лука, перехватчик Axios не нужен, потому что модель лука лучше, чем перехватчик Axios.

  1. Объявите класс MiddleWareManager, который является конкретной реализацией луковой модели. Код выглядит следующим образом.
// 中间件管理器,用于添加,删除中间件。
// 另外这个添加的中间件给谁用,也需要用参数(job)保存起来。
class MiddleWareManager {
  // 添加的中间件是给谁用的,我们用job标识,如果中间件是给axios用,那么这个job就是axios方法。
  // middleWares用来保存中间件。
  // job和中间件都是返回Promise对象的方法。
  // 其中,job接受一个参数config,由最后一个中间件传递。
  // 中间件接受两个参数,一个是他之前的中间件传递的config,一个是执行下一个中间件的方法。
  constructor(job) {
    // 这里默认加上axios请求
    this.job = job;
    this.middleWares = [];
  }

  use(middleWare) {
    this.middleWares.unshift(middleWare);
    return this;
  }

  remove(middleWare) {
    const index = this.middleWares.indexOf(middleWare);
    this.middleWares.splice(index, 1);
    return this;
  }

  run(config) {
    const { length } = this.middleWares;
    function innerRun(config, index) {
      // 如果中间件已经执行完毕,这直接job函数。
      if (index >= length) {
        return this.job(config);
      }
      // 否则执行下一个中间件函数
      return this.middleWares[index](config, (config) => innerRun(config, index++));
    }
    innerRun(config, 0);
  }
}

  1. MiddleWareManager реализован, следующим шагом будет объяснение того, как использовать MiddleWareManager и axios вместе. Мы определим метод запроса, и когда нам нужно отправить запрос, мы будем вызывать метод запроса единообразно.

// middleWare1用于处理是否需要全局的显示loading
async function middleWare1(config, next) {
  // 查看config中是否有showLoading标记,如果没有或者为true, 则需要全局显示loading, 
  // 当接收到响应后,自然需要关闭loading
  // 自然收到响应后,根据这个标记确定是否需要关闭loading
  const { showLoading, ...rest } = config;
  if (showLoading !== false) {
    // 显示loading动画
  }
  const response = await next(rest);
  if (showLoading !== false) {
    // 关闭动画
  }
  return response;
}

// 组装MiddleWareManager
const manager = new MiddleWareManager(axios);
manager.use(middleWare1);

// 实现request方法,用于发送请求
function request(config) {
  return manager.run(config);
}

  1. Когда мы отправляем запрос и нам нужно открыть загрузку глобально, делаем следующее

request({
  url: 'xxx',
  method: 'get'
})

Таким образом, загрузка будет автоматически открыта перед отправкой запроса, а загрузка будет автоматически закрыта при получении ответа. Когда нам не нужно автоматически открывать функцию загрузки, нам нужно только добавить showLoading: false в конфиг при отправке запроса, код такой


request({
  url: 'xxx',
  method: 'get',
  showLoading: false
})

Соответствует ли это требованиям внутренних коллег? А еще луковичная модель удобнее в использовании, чем перехватчики, особенно при обращении к одним и тем же переменным в запросе и ответе. Так же, как showLoading в нашем примере.Конечно, мы также можем переместить больше функций в перехватчике в промежуточное ПО луковой модели, например, автоматическое добавление токенов при отправке запросов.