---
# System prepended metadata

title: 面試考題 2024 - Promise.All()

---

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

![image](https://hackmd.io/_uploads/ryWGwvg70.png)


---
###### 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.

![image](https://hackmd.io/_uploads/Byu0I3eX0.png)

簡單地介紹 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
![image alt](https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExYXg4Znc1MDNtYnZydXE0aDNxNmh0dnhscjU3YzhpcmJjaHVwMjJjaiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/fxe8v45NNXFd4jdaNI/giphy.gif)
