面試考題 2024 - Promise.All()(實作)
===

---
###### tags: `面試問題`, `練習問題`, `2024`
當印度面試官發問:"We have to call 2 APIs, but the APIs didnt have any dependency, but we looking a solution how APIs working one by one?"
翻譯: “有兩隻API,兩個API都沒有相依沒有依賴,但是要都完成後才可以call下一個。”
這時候呢,我們可能會想到... PROMISE.ALL() !!
The **Promise.all()** is a build-in helper that accepts an array of promises (or generally an iterable). The function returns a promise from where you can extract promises resolved values using a **then-able** syntax.

簡單地介紹 Promise.all() :
* 接收一個內有多個 promises 的 Iterable, 例如 Array, Map , Set。
* 如果 Iterable 是空的,例如空 Array, 則 fulfilled值會是空的 Array。
* 如果 Iterable 不是空的,則如果所有的 promises 都fulfilled的話,則依序回傳 fulfilled 的值。如果其中有一個promise 被 rejected呢,則會馬上reject。
## 問題的答案範例:
```jsx
function fetchAPI1(){
return fetch("https://api.example.com/data1");
}
function fetchAPI2(){
return fetch("https://api.example.com/data2");
}
Promise.all([fetchAPI1,fetchAPI2])
.then(returns =>{
// results 是一個數組,包含兩個 API請求的響應結果
//解開api1,api2
const [response1, response2] = results;
//在這裡處理兩個響應的數據
return response1.json().then(data1 =>{
console.log("Data from API 1:", data1);
return response2.json();
}).then(data2 =>{
console.log("Data from API 2:", data2);
//進行下一步操控, 例如調用另一個函數等等等
});
})
.catch(error =>{
// 如果任何一個請求失敗,都會進入這個 catch 塊
console.log("Error fetching data:", error);
});
```
* **fetchAPI1** 和 **fetchAPI2** 分別啟動兩個API請求。
* **Promise.all** 接受一個包含這兩個請求的promise數組,並返回一個新的promise。
* 這個新的 promise 會在所有**包含的 promise** 都成功完成時解決,其結果是一個響應數組。
* 如果任一個請求失敗, **Promise.all** 返回的promise 將會拒絕,並併入 catch 裡。
* 其實Promise.all 可以接受多個API,然後再客製化說要怎麼做,return 第二個API,然後然後然後,再return 第三個API 以此類推。
## 我在專案類似的寫法(SSR):
```jsx!
type IndexType = {
mainCategorySlug?:string;
subCategorySlug?:string;
} & ServerSidePageType;
export default async function IndexPage({
mainCategorySlug,subCategorySlug,
params:{lang}
} : IndexType){
if(!locales.includes(lang)) return;
// 源自RTK call Api的方式
const categoriesData = await getCategoryApi({lang});
let productData: FetchResponse<Product的type>= {
status: 200, data: {} as Product的Type;
};
const error = [];
if(categoriesData.status === 200){
let wrongCategory = false;
if(
subCategorySlug &&
!categoriesData.data
.flatMap(mainCategory => mainCategory?.subcategories?.flatMap
(category => category.slug === subCategorySlug)).filter(isFound => isFound)?.length
){
//這裡寫了很多其實就是要告訴別人說
//就是找不到的話,就說category 出錯了!
wrongCategory = true;
}
}
if(
!wrongCategory &&
mainCategorySlug &&
!categoriesData.data.find(category => category.slug === mainCategorySlug)
){
//第二個判斷 category 返回錯誤的話
wrongCategory = true;
}
if(wrongCategory) redirect(...) //如果錯了,就去哪裡吧
if(categoriesData.status === 200){
productData = await getProductApi<...>({
lang,
category: mainCategorySlug ?
decodeURIComponent(mainCategorySlug):
decodeURIComponent(categoriesData?.data?.[0]?.slug),
subcategory: SubCategorySlug ? decodeURIComponent(subCategorySlug) : undefined,
});
}else {
error.push({
api: "category",
error: typeof categoriesData.error === "string"? categoriesData.error : JSON.stringify(categoriesData.error),
});
}
if(productData.status !== 200){
error.push({
api: "category",
error: typeof categoriesData.error === "string"? categoriesData.error : JSON.stringify(categoriesData.error),
});
}
return (
<IndexContainer
data=({
productList: productData.data.productList,
categories: categories.data,
})
mainCategorySlug={mainCategorySlug}
subCategorySlug={subCategorySlug}
/>
)
}
```
* 在這裡呢,做了幾個類似 catch的做法,因為category的是否有拿到資料是關重要,但一旦category通過了,productList一定可以。
* 越過兩個catch的判斷以後,就當category的status === 200的時候,就接著去取productList去再次呼叫API,感覺這裡就像promise.all裡面的第一個完成以後,就return API2 ,然後把裡面的list,逐一去實現。當然如果category叫不到,就連同 productList也一樣失敗,然後return ;
我覺得這是可以被參考的,但也算是參考了Promise.all 架構去設計了一系列的呼叫,我覺得拆開來寫,可能比較好管理。(?)
那Promise.all的介紹就到這裡,相信應付以上的問題應該都可以回答吧?
如果有其他可探討的事情隨時歡迎留言讓我知道,讓我們一起面試加油!PEACE
