<pre style="outline: 0px;font-family: monospace, monospace;font-size: 16px;text-align: left;color: rgb(63, 63, 63);letter-spacing: 0.544px;background-color: rgb(255, 255, 255);word-spacing: 0.8px;visibility: visible;">我發現很多人只知道如何常規地使用promise。</pre>
在js項目中,promise的使用應該是必不可少的,但我發現在同事和面試官中,很多中級以上的前端仍然堅持promiseInst.then()、promiseInst.catch()、Promise等常規用法等等。即使是 async/await 他們也只知道它但不知道為什么要使用它。
但實際上,Promise 有很多巧妙的高級用法,并且一些高級用法在 alova 請求策略庫內部也被廣泛使用。
現在,我將與大家分享8個高級使用技巧。希望這些技巧能夠對你有所幫助,現在,我們就開始吧。
1. Promise數組的串行執行
例如,如果你有一組接口需要串行執行,你可能首先想到使用await。
const requestAry = [() => api.request1(), () => api.request2(), () => api.request3()];
如果使用promise,可以使用then函數串聯多個promise,實現串行執行。
const requestAry = [() => api.request1(), () => api.request2(), () => api.request3()];
2. 在新的 Promise 范圍之外更改狀態
假設你有多個頁面,其功能要求在允許使用之前收集用戶信息。點擊使用某個功能之前,會彈出一個彈框進行信息收集。你會如何實施這個?
以下是不同級別前端同學的實現思路:
初級前端:我寫一個模態框,然后復制粘貼到其他頁面。效率非常高!
中級前端:這個不好維護。我們需要單獨封裝這個組件,并在需要的頁面引入!
高級前端:安裝任何密封的東西!!!把方法調用寫在所有頁面都可以調用的地方不是更好嗎?
想要了解高級前端是如何實現的,以vue3為例,看一下下面的例子。
<!-- App.vue -->
接下來,getInfoByModal就可以通過直接調用模態框來輕松獲取用戶填寫的數據。
<template>
這也是很多UI組件庫中封裝常用組件的一種方式。
3. async/await 的替代用法
很多人只知道它是用來在調用await時接收async函數的返回值的,卻不知道async函數它實際上是一個返回promise的函數。例如,以下兩個函數是等效的:
const fn1 = async () => 1;
在大多數情況下,await 會跟隨 Promise 對象并等待它完全填充。因此,下面的 fn1 函數 wait 也是等價的:
await fn1();
然而,await也有一個鮮為人知的秘密。當它后面跟的值不是promise對象時,它會用promise對象包裝該值,所以await后面的代碼必須異步執行。例子:
Promise.resolve().then(() => {
相當于
Promise.resolve().then(() => {
4. 承諾實施請求共享
當一個請求已經發出但尚未得到響應時,再次發出相同的請求,就會造成請求的浪費。此時,我們可以將第一個請求的響應與第二個請求共享。
request('GET', '/test-api').then(response1 => {
上述兩個請求實際上只發送一次,同時收到相同的響應值。
那么,請求共享有哪些使用場景呢?我認為有以下三個:
當頁面渲染多個內部組件同時獲取數據時;
提交按鈕未禁用且用戶連續多次點擊提交按鈕;
預加載數據的情況下,預加載完成之前進入預加載頁面;
這也是alova的高級功能之一。要實現請求共享,需要使用promise的緩存功能,即一個promise對象可以通過多次await獲取數據。簡單的實現思路如下:
const pendingPromises = {};
上述兩個請求實際上只發送一次,同時收到相同的響應值。
那么,請求共享有哪些使用場景呢?我認為有以下三個:
當頁面渲染多個內部組件同時獲取數據時;
提交按鈕未禁用且用戶連續多次點擊提交按鈕;
預加載數據的情況下,預加載完成之前進入預加載頁面;
這也是alova的高級功能之一。要實現請求共享,需要使用promise的緩存功能,即一個promise對象可以通過多次await獲取數據。簡單的實現思路如下:
const promise = new Promise((resolve, reject) => {
正確答案是已滿狀態。我們只需要記住,一旦待處理的promise從一種狀態轉移到另一種狀態,就無法更改。因此,例子中是先轉為fulfilled狀態,然后reject()就不會再轉為rejected狀態。
6.徹底明確then/catch/finally返回值
一句話概括就是,上面三個函數都會返回一個新的promise包裝對象。包裝后的值是執行回調函數的返回值。如果回調函數拋出錯誤,它將包裝拒絕狀態承諾。似乎不太容易理解,我們來看一個例子:
我們可以將它們一一復制到瀏覽器控制臺并運行它們以幫助理解。
// then function
7、then函數的第二次回調和catch回調有什么區別?
當請求發生錯誤時,會觸發 Promise 的 then 的第二個回調函數和 catch。乍一看沒有區別,但實際上前者無法捕獲then當前第一個回調函數中拋出的錯誤,但catch可以。
Promise.resolve().then(
原理就如上一點所說的。catch 函數是在 then 函數返回的處于拒絕狀態的 Promise 上調用的,因此它的錯誤自然可以被捕獲。
8.(最終)Promise實現koa2洋蔥中間件模型
koa2框架引入了洋蔥模型,可以讓你的請求像剝洋蔥一樣一層層進去,再一層層出來,從而實現請求前后處理的統一。
我們來看一個簡單的 koa2 洋蔥模型:
const app = new Koa();
上面的輸出是a-start -> b-start -> b-end -> a-end,這樣神奇的輸出序列是如何實現的呢?有人沒天賦,簡單的用20行左右的代碼就實現了。如有雷同,純屬巧合。
接下來我們分析一下
注:以下內容對新手不友好,請謹慎閱讀。
首先先保存中間件函數,在listen函數中收到請求后調用洋蔥模型執行。
function action(koaInstance, ctx) {
收到請求后,從第一個中間件開始串行執行next之前的前置邏輯。
//Start to start middleware call
處理next之后的post邏輯
function action(koaInstance, ctx) {
至此,一個簡單的洋蔥模型就已經實現了。
總結
以上就是我今天想與你分享的8個關于Promise的高級用途的全部內容,如果你覺得有用的話,請記得點贊我,關注我,并將這個內容分享給你的小伙伴們,也許能夠幫助到他。
最后,感謝你的閱讀,祝編程愉快!