iT邦幫忙

2021 iThome 鐵人賽

DAY 24
1
自我挑戰組

JavaScript 奇奇怪怪的核心觀念系列 第 24

(Day24) 處理非同步的 Promise

前言

在過去 JS 要處理 Ajax 這個非同步語法,會很容易用到 Callback 寫法,而 Callback 不但不好管理,還容易寫成 Callback Hell,如圖:

幸好 ES6 新增了 Promise ,對於 JS 這個單執行序的語言 Promise 非常實用。
Promise 直接翻譯成中文會是承諾 ,而 Promise 的使用結果也就分成兩種

  • 達成承諾,使用 resolve()
  • 承諾失敗,使用 reject()

實際使用 Promise

而要使用 Promise 大致上分為兩個步驟:

  • 使用 new Promise() 的函式建構式創造一個新的 Promise 物件
  • 實際執行上面提到的 Promise 物件

在創造函式建構式時,函式建構式會帶上兩個參數 resolvereject , 第一個參數是用來執行 成功的方法,第二個則是 失敗的方法,這兩個參數名稱接可以自定義,不過實際開發時多數,仍會使用這個名稱做命名。
(這邊是把 Promise 寫成函式方法,因此可以帶入參數,在透過參數來做判斷。)

function PromiseFn(String) {
	// 創造建構函式並帶上 resolve 、 reject 參數
  return new Promise((resolve, reject) => {
    setTimeout(function () {
        // Promise 承諾的判斷
      if (String.length >= 5) {
        resolve(`Promise 成功, ${ String } 共 ${ String.length } 個字 `)
      } else {
        reject('Promise 失敗')
      }
    }, 2000);
  });
}

建立好 Promise 函式建構式後,便是執行 Promise 本身了,接者執行 Promise 本身時,我們可以使用 then()catch() 他們會分別接收 Promise 成功 以及 Promise 失敗的結果,但他們需要寫上一個 Callback Function ,若要顯示 Promise 建構式中的 resolve()reject() 設定的資料,那麼會需要在 Callback Function 中帶上一個參數,這些參數就會顯示 resolve()reject() 設定的資料:

function PromiseFn(String) {
  return new Promise((resolve, reject) => {
    setTimeout(function () {
      if (String.length >= 5) {
        resolve(`Promise 成功, ${ String } 共 ${ String.length } 個字 `)
      } else {
        reject('Promise 失敗')
      }
    }, 2000);
  });
}

PromiseFn('test')// Promise 失敗

.then((res)=>{ // 第一個參數會回傳 resolve() 設定資料
  console.log(res)  
})
.catch((err)=>{
  console.log(err) // 第一個參數會回傳 reject() 設定資料
})

PromiseFn('Ryder') //Promise 成功, Ryder 共 5 個字
.then((res)=>{
  console.log(res)
})
.catch((err)=>{
  console.log(err)
})

All 與 Race

扣除上面的 Promise 基本方法,Promise 還提供 Promise.all()Promise.race() 兩種用法。

  • 使用 Promise.all() 時,會執行 Promise.all() 中所有的 Promise 方法,並將回傳一個陣列,而這個陣列就是 resolve() 所提供的。
function PromiseFn(String) {
  return new Promise((resolve, reject) => {
    setTimeout(function () {
      if (String.length >= 5) {
        resolve(`Promise 成功, ${ String } 共 ${ String.length } 個字 `)
      } else {
        reject('Promise 失敗')
      }
    }, 2000);
  });
}

Promise.all([PromiseFn('Ryder'), PromiseFn('youtube')]).then((res)=>{
	console.log(res) //['Promise 成功, Ryder 共 5 個字 ', 'Promise 成功, youtube 共 7 個字 ']
})
  • Promise.race()Promise.all() 一樣,會同時執行 Promise.race() 中所有 Promise 方法,但他只會回傳最快執行完畢的 Promise 方法。
const p = new Promise((resolve) => {
  if (true) {
    resolve(`直接執行 Promise`)
  }
})
function PromiseFn(String) {
  return new Promise((resolve, reject) => {
    setTimeout(function () {
      if (String.length >= 5) {
        resolve(`Promise 成功, ${String} 共 ${String.length} 個字 `)
      } else {
        reject('Promise 失敗')
      }
    }, 2000);
  });
}

Promise.race([PromiseFn('Ryder'), p]).then((res) => {
  console.log(res) //直接執行 Promise
})

鏈式寫法

上面介紹的 Promise.all() Promise.race() 都是會同時執行的方法,不過我們肯定會遇到需要依序執行 Promise 的狀況,在過去使用 Callback Function 時就會寫出超巢的 Callback Hell,不過 Promise 則提供了鏈式寫法,可以輕鬆的達成需求。
要使用 Promise 的鏈式寫法,只需要在 then() 中使用 return 並呼叫下一個 Promise 這樣變能使用 .then() 不斷串聯下去。

const p = new Promise((resolve) => {
  if (true) {
    resolve(`直接執行 Promise`)
  }
})

function PromiseFn(String) {
  return new Promise((resolve, reject) => {
    setTimeout(function () {
      if (String.length >= 5) {
        resolve(`Promise 成功, ${String} 共 ${String.length} 個字 `)
      } else {
        reject('Promise 失敗')
      }
    }, 2000);
  });
}
PromiseFn('Ryder')
  .then((res) => {
    console.log(res) // Promise 成功, Ryder 共 5 個字
    return PromiseFn('youtube') // Promise 鏈式寫法,可以不斷寫 Promise 下去。
  }).then((res) => {
    console.log(res)  // Promise 成功, youtube 共 7 個字 
    return p
  }).then((res) => {
    console.log(res) // 直接執行 Promise
  })

參考文獻


上一篇
(Day23) ES6 箭頭函式
下一篇
(Day25) Promise 語法糖 async/await
系列文
JavaScript 奇奇怪怪的核心觀念30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言