axios添加axios.all和axios.spread方法,與promise.all

1.前言
在官方 axios 中,還提供了 axios.all和axios.spread 這兩個方法,這兩個方法主要是爲了執行多個併發請求,官方文檔中,它們的用法示例如下:

function getUserAccount() {
  return axios.get('/user/12345');
}

function getUserPermissions() {
  return axios.get('/user/12345/permissions');
}

axios.all([getUserAccount(), getUserPermissions()])
  .then(axios.spread((acct, perms) => {
    // 兩個請求都完成後
  }));

從用法示例中可以看出:

axios.all方法接受一個數組作爲參數,數組中的每個元素都是一個請求,返回一個promise對象,當數組中所有請求均已完成時,執行then方法。
在then方法中執行了 axios.spread 方法。該方法是接收一個函數作爲參數,返回一個新的函數。接收的參數函數的參數是axios.all方法中每個請求返回的響應。
回到頂部
2. 窺探本質
2.1 axios.all本質
從axios.all方法的使用方式以及使用形式上看,是不是跟Promise.all方法很相似?對,沒錯,axios.all就是給Promise.all方法換了個名字而已,我們看看Promise.all方法是如何使用的,如下:

function getUserAccount() {
  return axios.get('/user/12345');
}

function getUserPermissions() {
  return axios.get('/user/12345/permissions');
}

Promise.all([getUserAccount(), getUserPermissions()])
  .then(([acct,perms]) => {
    // 兩個請求都完成後
  }));

我們可以看到,axios.all方法與Promise.all方法是一模一樣的,不管是使用方式還是傳入的參數都是一模一樣的。axios.all的本質搞明白以後我們再看看axios.spread的本質。

2.2 axios.spread本質
上文說了,axios.all方法與Promise.all方法是一模一樣的,唯一看起來不同的地方就是then方法,我們先來比較這兩個then方法中的內容:

// axios.all的then
axios.spread((acct, perms) => {})

// Promise.all的then
([acct,perms]) => {}

我們可以看到,Promise.all的then方法裏面是個函數,函數的參數是所有請求的響應組成的數組;而axios.all的then方法裏面調用了axios.spread方法,axios.spread方法接收一個函數作爲參數,該參數函數的參數也是所有請求的響應,既然上文說了axios.all方法與Promise.all方法是一模一樣的,那麼我們只需想辦法再讓兩個then方法相同即可。也就是說我們創建一個axios.spread方法並且讓axios.spread((acct, perms) => {})的返回值與([acct,perms]) => {}等價即可。

OK,搞清楚這兩個方法的本質以後,我們就來着手實現它們。

回到頂部
3. 方法接口類型定義
實現這兩個方法之前,我們先在src/types/index.ts中的AxiosStatic中爲這兩個方法添加接口類型,如下:

export interface AxiosStatic extends AxiosInstance {
  // 新增
  all<T>(promises: Array<T | Promise<T>>): Promise<T[]>;
  spread<T, R>(callback: (...args: T[]) => R): (arr: T[]) => R;
}

添加好之後接下來就來實現這兩個方法。

回到頂部
4. 方法實現
這兩個方法是掛載到axios混合對象上的,那麼我們就在src/axios.ts中實現這兩個方法,並將其掛載到axios上,如下:

axios.all = function(promises) {
  return Promise.all(promises);
};
axios.spread = function(callback) {
  return function wrap(arr) {
    return callback.apply(null, arr);
  };
};

根據第2章的分析:

axios.all方法就是對Promise.all方法進行了一層包裝,本質上是一模一樣的,沒有任何額外的邏輯,所以調用axios.all方法就是調用了Promise.all方法。
對於axios.spread方法,根據我們的分析結果只需讓axios.spread((acct, perms) => {})的返回值與([acct,perms]) => {}等價即可。
OK,這樣就把這兩個方法實現完畢了,接下來我們來編寫demo來測試下效果如何。

回到頂部
5. demo編寫
在 examples 目錄下創建 allAndSpread目錄,在 allAndSpread目錄下創建 index.html:

allAndSpread demo

接着再創建 app.ts 作爲入口文件:

import axios from "../../src/axios";

function getA() {
  return axios.get("/api/allAndSpreadA");
}

function getB() {
  return axios.get("/api/allAndSpreadB");
}

axios.all([getA(), getB()]).then(
  axios.spread(function(resA, resB) {
    console.log(resA.data);
    console.log(resB.data);
  })
);

axios.all([getA(), getB()]).then(([resA, resB]) => {
  console.log(resA.data);
  console.log(resB.data);
});

接着在 server/server.js 添加新的接口路由:

// 添加axios.all和axios.spread方法

router.get("/api/allAndSpreadA", function(req, res) {
  res.json({
    data: "allAndSpreadA"
  });
});
router.get("/api/allAndSpreadB", function(req, res) {
  res.json({
    data: "allAndSpreadB"
  });
});

最後在根目錄下的index.html中加上啓動該demo的入口:

  • allAndSpread
  • OK,我們在命令行中執行:

    同時開啓客戶端和服務端

    npm run server | npm start
    接着我們打開 chrome 瀏覽器,訪問 http://localhost:8000/ 即可訪問我們的 demo 了,我們點擊 allAndSpread,就可以看到兩個請求都已經正常發出,並且打開F12中的控制檯可以看到兩個請求的響應都已經返回了。
    在這裏插入圖片描述

    發表評論
    所有評論
    還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
    相關文章