ES6(三) Promise 的基本使用方式

語言: CN / TW / HK

基本用法

關於Promise的資料,網上有很多了,這裡簡單粗暴一點,直接上程式碼。
假設我們要做一個訪問後端API的函式,那麼我們可以這樣模擬一下。

    const mySend = (url, data) => {
      // 接收url 和data,假裝向後端提交
      console.log('url:', url, data)
      // 定義一個例項
      const p = new Promise((resolve, reject)=>{
        // resolve,reject是形式引數,可以是任意寫法,如(res, rej)
        // 預設第一個引數實現的是resolve功能;
        // 第二個引數實現的是reject功能。
        console.log("假裝訪問了一下後端,並且獲得了資料。")
        const data = {
          name: 'jyk',
          time: new Date().valueOf()
        }
        // 成功了,返回給呼叫者
        resolve(data) 
        // 不同於return, resolve()執行完成後後面的程式碼還會執行。
        console.log('resolve後的程式碼')
        // 如果 resolve 被呼叫了,那麼 reject 就不會被呼叫了。
        // 失敗的話,呼叫reject返回給呼叫者。
        reject('失敗了')
      })
      return p
    }
  • new Promise
    先定義一個函式,用於接收呼叫者的引數。
    然後生成一個Promise的例項,在裡面進行我們想要的操作。

  • resolve(data)
    如果操作成功就呼叫 resolve(data) ,返回給呼叫者;

  • reject('失敗了')
    如果操作失敗,就呼叫reject('失敗了') ,返回給呼叫者。

注意:返回引數只能有一個,不支援多個引數,如果需要返回多個,可以組成一個物件。

有些例子會用setTimeout做演示,其實效果都一樣,不是必須弄個非同步的方式來模擬。

單次呼叫

函式寫好了,怎麼呼叫呢?其實呼叫方法和axios的使用方式很像,因為axios也是用promis封裝的。

  const submit = () => {
      mySend('/api/person', {id: 122})
        .then((data) => {
          console.log('回撥資料:', data)
        })
        .catch((error) => {
          console.log(error)
        })
    }

呼叫很簡單,看著也非常眼熟對吧。

  • then 響應成功的回撥,

  • catch 響應失敗(異常)的回撥。

  • 執行結果:

url-data: /api/person {id: 122}
(index):32 假裝訪問了一下後端,並且獲得了資料。
(index):39 resolve後的程式碼
(index):52 回撥資料: {name: "jyk", time: 1612084395672}

依次呼叫

如果要多次呼叫呢?而且要得到上一次返回的資料,才能發起下一次的訪問。

  const submitStep = () => {
      mySend('/api/person1', [1,2,3]).then((data) => {
        console.log('第一個返回:', data)
        return mySend('/api/person2', data) // 發起第二次請求
      }).then((data) => {
        console.log('第二個返回:', data)
        return mySend('/api/person3', data) // 發起第三次請求
      }).then((data) => {
        console.log('第三個返回:', data)
        return mySend('/api/person4', data) // 發起第四次請求
      }).then((data) => {
        console.log('第四個返回:', data)
      })
    }

第一次呼叫的回撥函式裡面,使用return的方式,發起下一次呼叫。這樣就可以避免回撥地域。

  • 執行結果:
url-data: /api/person1 (3) [1, 2, 3]
(index):32 假裝訪問了一下後端,並且獲得了資料。
(index):39 resolve後的程式碼
(index):62 第一個返回: {name: "jyk", time: 1612084751425}
(index):26 url-data: /api/person2 {name: "jyk", time: 1612084751425}
(index):32 假裝訪問了一下後端,並且獲得了資料。
(index):39 resolve後的程式碼
(index):65 第二個返回: {name: "jyk", time: 1612084751426}
(index):26 url-data: /api/person3 {name: "jyk", time: 1612084751426}
(index):32 假裝訪問了一下後端,並且獲得了資料。
(index):39 resolve後的程式碼
(index):68 第三個返回: {name: "jyk", time: 1612084751428}
(index):26 url-data: /api/person4 {name: "jyk", time: 1612084751428}
(index):32 假裝訪問了一下後端,並且獲得了資料。
(index):39 resolve後的程式碼
(index):71 第四個返回: {name: "jyk", time: 1612084751430}

可以注意一下time的值,前後是對應的。

批量呼叫

如果下次呼叫不需要上一次的結果呢?那麼能不能一起呼叫呢?當然是可以的。

    const submitMore = () => {
      Promise.all([
        mySend('/api/person11', [1,2,3]),
        mySend('/api/person22', [4,5,6]),
        mySend('/api/person33', [7,8,9])
      ]).then((data) => {
        console.log("一起呼叫,一起返回:")
        console.log('data:', data)
        console.log('data11:', data[0])
        console.log('data22:', data[1])
        console.log('data33:', data[2])
      },(msg) => {
        console.log(msg)
      })
    }
  • Promise.all
    使用 Promise.all,把呼叫寫成陣列的形式。
    返回的data也是一個數組的形式,其順序會對照上面的呼叫順序。

  • 執行結果:

url-data: /api/person11 (3) [1, 2, 3]
(index):32 假裝訪問了一下後端,並且獲得了資料。
(index):39 resolve後的程式碼
(index):26 url-data: /api/person22 (3) [4, 5, 6]
(index):32 假裝訪問了一下後端,並且獲得了資料。
(index):39 resolve後的程式碼
(index):26 url-data: /api/person33 (3) [7, 8, 9]
(index):32 假裝訪問了一下後端,並且獲得了資料。
(index):39 resolve後的程式碼
(index):82 一起呼叫,一起返回:
(index):83 data: (3) [{…}, {…}, {…}]
  0: {name: "jyk", time: 1612085029968}
  1: {name: "jyk", time: 1612085029969}
  2: {name: "jyk", time: 1612085029970}
  length: 3__proto__: Array(0)
(index):84 data11: {name: "jyk", time: 1612085029968}
(index):85 data22: {name: "jyk", time: 1612085029969}
(index):86 data33: {name: "jyk", time: 1612085029970}

可以看到,先發起了申請,然後結果會一起返回。

小結

這樣看起來就不會暈了吧。我的想法是,先會用能夠執行起來,以後有空了在去研究原理和其他細節。

線上演示:http://naturefwvue.github.io/nf-vue-cnd/ES6/promise/

原始碼:http://github.com/naturefwvue/nf-vue-cnd/tree/main/ES6/promise