ES6 從 Callback 走向 Promise
ES6 提供了 Promise 的 API 讓我們不在為寫出可怕的 Callback 進入所謂的 Callback Hell 而煩惱。初學 Javascript 你可能不知不覺走入 Callback Hell 而不自覺而且會想知道 Callback Hell 長怎麼樣,可以參考下面這張圖 XD

Callbacks
舉個比較淺白一點的例子來看,我們在讀取一個檔案的內容時,用 Callback 的方法會像這樣做:
const fs = require('fs');const fileOne = 'hello.log';
fs.readFile(fileOne, 'utf-8', (error, results) => {
if (error) {
console.error(error);
} else {
console.log(results);
}
});你可能覺得看起來還好看起來還不像上面的 Callback Hell 情況那麼糟?因為Javascript 語言特性具有 Asynchronous(非同步)的特色,所以要在 readfile 完之後,想要做之事又恰是 I/O Tasks(具有依賴性)的程式邏輯必須要寫在上述 else 的條件裡面,否則將會並行!
這種情形很容易發生,例如我必須要依賴上一個檔案的結果,再去讀下一個檔案來做一些處理,於是乎程式將會變成:
const fs = require('fs');
const fileOne = 'hello.log';
const fileTwo = 'world.log';fs.readFile(fileOne, 'utf-8', (error, results1) => {
if (error) {
console.error(error);
} else {
fs.readFile(fileTwo, 'utf-8', (error, results2) => {
if (error) {
console.error(error);
} else {
console.log(results1 + results2);
}});
}
});
你可以看見,程式碼已經開始橫向發展了,如果再多一些 I/O Tasks 例如:根據讀取第二個檔案的結果去做 HTTP requests 勢必將寫在第二個 else 裡面讓程式碼變得難以閱讀跟維護。
Promise
首先我們可以將第一次要讀的檔案包裝成 Promise 物件,透過 Promise API 來包裝 Callbacks 讓程式碼更好閱讀,這是包裝
'use strict';
const fs = require('fs');
let read = function (file) {
let promise = new Promise((resolve, reject) => {
fs.readFile(file, ‘utf-8’, (error, results) => {
if (error) reject(new Error(error));
else resolve(results);
});
});return promise;
};
resolve 和 reject 是 Javascript 提供的函式,resolve 是 Promise 物件的狀態從 Pending 變為 Resolved 並將結果傳出去(通常在操作成功的情況下呼叫 resolve)
reject 則是 Promise 物件的狀態從 Pending 變為 Rejected 並將錯誤結果傳出去(通常在操作失敗的情況下呼叫 resolve)
包裝好之後你就可以用 Promise 的 then 方法來 call 你自己的 API
const fs = require('fs');
const fileOne = 'hello.log';
const fileTwo = 'world.log';read(fileOne)
.then((results) => {
console.log(results);
}).then(() => {
return read(fileTwo);
}).then((results) => {
console.log(results);
}).catch((err) => {
console.log(err);
});
在 then 裡面就能夠寫你想要再讀一個檔案之後,想要做的其他 I/O tasks 當有 Error 發生會被 catch 接到。