[鐵人賽 2022-擊敗前端面試大作戰] Promise
來到擊敗前端面試大作戰系列的第三篇,今天要來討論前端工程師百寶袋中必備的一項工具---Promise.
什麼是 Promise?
回答:Promise 是 ES6 裡所提出的,透過其提供的內建方法包含 all, race, resolve, reject 等來處理非同步。
為什麽需要 Promise?
Promise 解決了回乎地獄(callback hell)的問題,過去在處理非同步時會使用回乎函式來處理,但是當程式碼一多就會造成可讀性跟 debug 上的困難。透過 Promise 的語法,我們可以用簡潔的語法來處理這些問題。
Promise 介紹
Promise 為一個建構函式,裡面要放 executor 也就是一個帶有 resolve, reject 的函式,在非同步處理完成後,可以用 resolve 來回傳成功結果,用 reject 來回傳失敗結果。下面我們來看一下 Promise 跟 async/await 的範例。
new Promise( /* executor */ function(resolve, reject) { ... } );
let promise = new Promise(function (resolve, reject) {
resolve(1); //執行成功,下面的promise or reject不會繼續執行。
setTimeout(() => resolve(2), 1000);
reject('failed)
});
promise.then(alert); // 1
注意: 當執行到 promise 中的 resolve or reject 後,後面的 promise or reject 就不會再執行了。
Async/await
原生方法讓我們可以用更直觀的方式來處理 Promise
//使用async await
async function wait() {
await new Promise((resolve) => setTimeout(resolve, 1000));
return 10;
}
function f() {
// shows 10 after 1 second
wait().then((result) => alert(result));
}
f();
Promise 常用的地方包含在用 fetch 拿資料的時候,會回傳一個 Promise 物件,這時候就可以用其提供的各種語法,讓我們在處理非同步時更方便!
什麼是 Fetch?
一個原生方法用來處理 call api 需求,會回傳一個 Promise 物件。
let response = await fetch("/article/fetch/post/user", {
method: "POST",
headers: {
"Content-Type": "application/json;charset=utf-8",
},
body: JSON.stringify(user),
});
以上就為 Promise 的簡略介紹,更詳細的介紹我推薦這一篇由卡斯柏所寫的文章,我覺得他很詳細地把 Promise 的功能用容易理解的方式寫出來~ 卡斯柏's Promise 介紹
下面我們會繼續介紹一些很常見的 Promise 面試題!
常見的 Promise 面試題
Promise.all vs Promise.race?
回答:
- Promise.all 多個 Promise 行為同時執行,全部完成後統一回傳。
- Promise.race 多個 Promise 同時執行,但僅回傳第一個完成的。
什麼是 Promise 中的 finally?
回答:
promise 中的 finally 用於處理額外的狀況,他有兩個重點。
- finally 函式沒有辦法傳遞 promise 的值,代表你在 finally 中拿不到 Promise 的值。
- finally 會忽略裡面的 return 然後執行下一階段。
//finally
new Promise((resolve, reject) => {
/* do something that takes time, and then call resolve or maybe reject */
})
// runs when the promise is settled, doesn't matter successfully or not
.finally(() => stop loading indicator)
// so the loading indicator is always stopped before we go on
.then(result => show result, err => show error)
Promise 一個等一個
async function readFiles(files) {
for (const file of files) {
await readFile(file);
}
}
注意:Promise 不能拿來在 ForEach 中使用,會有 race condition 的問題,原因是 ForEach 不會等待 await 完成,因此結果會是錯誤的順序或者是完全遺失
範例:
async function asyncFunction() {
const myArray = [1, 2, 3];
const promises = [];
myArray.forEach(async (num) => {
const result = await fetch(
`https://jsonplaceholder.typicode.com/todos/${num}`
);
console.log(result.json());
});
}
asyncFunction();
// [2,3,4] // wrong answer
//正確處理Promise的方法應該要像這樣
async function asyncFunction() {
const myArray = [1, 2, 3];
const promises = myArray.map(async (num) => {
const result = await fetch(
`https://jsonplaceholder.typicode.com/todos/${num}`
);
return result.json();
});
const results = await Promise.all(promises);
console.log(results);
}
asyncFunction();
那關於 Promise 的介紹就到這裡拉~但是除了上面提到的東西外,Promise 在面試中還有另外一種很常見的考法,就是實做 Promise.race, Promise.all 的語法,這部分我們就會留到明天再跟大家分享了,我們明天見!
Resource:
https://www.casper.tw/development/2020/02/16/all-new-promise/ https://javascript.info/promise-basics https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Promise https://javascript.info/async-await https://javascript.info/fetch https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/140 https://segmentfault.com/a/1190000039775255