Lala Code

Lala 的前端大補帖,歡迎一起鑽研前端技術😊

0%

ES6-Promise 非同步的解決方案

Imgur

由於非同步的程式沒辦法照順序執行,像是 AJAX、setTimeout 都是典型的非同步,ES6 提出了 Promise 的新物件,可以確保非同步處理完畢後,再進行下一步的動作,Promise 就是來解決非同步的程式碼。

Promise 物件的三種狀態

在建立 Promise 之前,先來了解 Promise 只會出現以下三種狀態

  1. pending 初始狀態 (進行中)
  2. fulfilled 事件已完成,回傳 resolve 的結果
  3. rejected 事件已失敗,回傳 rejected 的結果

Promise 狀態的改變只有兩種可能
從 pending 變成 fulfilled
從 pending 變成 rejected
而一但狀態改變就會固定,永遠不會再改變狀態了。


建立一個 Promise 物件

1
2
3
4
5
6
7
var promise = new Promise(function (resolve, reject) {
if (true) {
resolve('成功');
} else {
reject('失敗');
}
});
  1. 創建一個新 Promise 構造函數,並代入一個 function
  2. function 代入兩個參數,這兩個參數也是函式,分別為 resolve (執行成功)、reject (執行失敗)
  3. 設定 resolve / reject 回傳方法
    resolve() 執行成功的函式
    reject() 執行失敗的函式

取得 Promise 結果

Promise 物件生成後,可以用 Promise 的原型方法來執行取得的結果

.then()

綁定當 fulfilled 或 rejected 狀態時,分別要執行的函數,.then 可傳入兩個參數

1
2
3
4
5
6
7
8
9
10
11
promise.then(
function (value) {
// 當狀態是 fulfilled (成功) 時,執行這個函數
// value 是透過 resolve() 傳進來的參數
},
function (error) {
// 當狀態是 rejected (失敗) 時,執行這個函數
// error 是透過 reject() 傳進來的參數
// 此參數選擇性的,不一定需要
}
);

.catch()

綁定當 rejected 狀態時,要執行的函數

1
2
3
promise.catch(function (error) {
console.log(error);
});

.finally()

不帶有任何參數,表示非同步執行完畢,無論是否正確完成,要執行的函數

1
2
3
4
5
6
7
promise
.then((success) => {
console.log(success);
})
.finally(() => {
console.log('done');
});

Chaining 串接

then、catch 執行後都會返回一個新的 Promise 物件,可以使用鏈接的方式不斷的進行
後面的 then 會接收前一個 then 的 return value 當作參數

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var promise = new Promise(function (resolve, reject) {
resolve('123');
});

promise
.then(function (str) {
return str + ' 456';
})
.then(function (str) {
return str;
})
.then(function (str) {
console.log(str); // 123456
});

Promise 方法介紹

Promise.all(iterable)

透過陣列的形式傳入多個 promise 函式,Promise.all 會回傳一個陣列,分別有三種情況

  1. 當引數 iterable 中所有的 promises 都被實現(resolved)
  2. 引數 iterable 不含任何 promise 時,被實現
  3. 得到一個 rejected 時,第一個被 reject 的值會被傳進回 all Promise 物件的 callback

當全部執行完成後回傳陣列結果,陣列的結果順序與傳入的順序一致,適合用在多支 API 要一起執行,並確保全部完成後才進行其他工作時

1
2
3
4
5
6
7
8
9
10
11
var p1 = Promise.resolve(3);

var p2 = 123;

var p3 = new Promise(function (resolve, reject) {
setTimeout(resolve, 100, 'foo');
});

Promise.all([p1, p2, p3]).then(function (values) {
console.log(values); // [3, 123, "foo"]
});

Promise.race(iterable)

透過陣列的形式傳入多個 promise 函式,Promise.race 的結果為第一個最先改變狀態的 Promise 物件

1
2
3
4
5
6
7
8
9
10
var p1 = new Promise(function (resolve, reject) {
setTimeout(resolve, 500, 'one');
});
var p2 = new Promise(function (resolve, reject) {
setTimeout(resolve, 100, 'two');
});

Promise.race([p1, p2]).then(function (value) {
console.log(value); // 會顯示 "two",因為 p2 比較快被 resolve
});

Promise.resolve(value)

直接定義 Promise 物件 resolve 的狀態,回傳一個 Promise 物件,value 有三種可能

  1. value 為具有”then”方法的 Promise,回傳的 promise 將依其結果採取其最終狀態
  2. value 為 promise,呼叫 Promise.resolve 之結果
  3. 其他情形都將回傳以 value 實現的 promise
1
2
3
4
5
6
7
8
9
10
Promise.resolve('Success').then(
function (value) {
console.log(value);
},
function (value) {
console.log('Fail');
}
);

// 輸出 "Success"

Promise.reject(reason)

回傳一個以 reason 拒絕的 Promise 物件

1
2
3
4
5
6
7
8
9
10
Promise.reject(new Error('Fail')).then(
function (error) {
console.log('Success');
},
function (error) {
console.log('Fail');
}
);

// 輸出 "Fail"




有了 Promise 非同步語法,就可以捨棄古早時期使用的 callback hell,變得更清楚直觀,程式碼可讀性更高了 👍


參考文獻: Fooish 程式技術MDN卡斯柏’s blog




Hey!想學習更多前端知識嗎?

最近 Lala 開了前端課程 👉【實地掌握RWD - 12小時新手實戰班】👈
無論您是 0 基礎新手,又或是想學 RWD 的初學者,
我們將帶你從零開始,深入了解並掌握 RWD 響應式網頁設計的核心技術,快來一起看看吧 😊



🚀線上課程分享

線上課程可以加速學習的時間,省去了不少看文件的時間XD,以下是我推薦的一些課程
想學習更多關於前後端的線上課程,可以參考看看。

Hahow

Hahow 有各式各樣類型的課程,而且是無限次數觀看,對學生或上班族而言,不用擔心被時間綁住



六角學院

如果你是初學者,非常推薦六角學院哦!
剛開始轉職也是上了六角的課,非常的淺顯易懂,最重要的是,隨時還有線上的助教幫你解決問題!


Udemy

Udemy 裡的課程非常的多,品質普遍不錯,且價格都滿實惠的,CP值很高!
也是很多工程師推薦的線上課程網站。
❤️