面試考題 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)