成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

八個(gè)關(guān)于 Promise 高級(jí)用途的技巧

開發(fā) 前端
在js項(xiàng)目中,promise的使用應(yīng)該是必不可少的,但我發(fā)現(xiàn)在同事和面試官中,很多中級(jí)以上的前端仍然堅(jiān)持promiseInst.then()、promiseInst.catch()、Promise等常規(guī)用法等等。即使是 async/await 他們也只知道它但不知道為什么要使用它。

前言

大家好,我是林三心,用最通俗易懂的話講最難的知識(shí)點(diǎn)是我的座右銘,基礎(chǔ)是進(jìn)階的前提是我的初心~

我發(fā)現(xiàn)很多人只知道如何常規(guī)地使用promise。

在js項(xiàng)目中,promise的使用應(yīng)該是必不可少的,但我發(fā)現(xiàn)在同事和面試官中,很多中級(jí)以上的前端仍然堅(jiān)持promiseInst.then()、promiseInst.catch()、Promise等常規(guī)用法等等。即使是 async/await 他們也只知道它但不知道為什么要使用它。

但實(shí)際上,Promise 有很多巧妙的高級(jí)用法,并且一些高級(jí)用法在 alova 請(qǐng)求策略庫(kù)內(nèi)部也被廣泛使用。

現(xiàn)在,我將與大家分享8個(gè)高級(jí)使用技巧。希望這些技巧能夠?qū)δ阌兴鶐椭?,現(xiàn)在,我們就開始吧。

1. Promise數(shù)組的串行執(zhí)行

例如,如果你有一組接口需要串行執(zhí)行,你可能首先想到使用await。

const requestAry = [() => api.request1(), () => api.request2(), () => api.request3()];
for (const requestItem of requestAry) {
  await requestItem();
}

如果使用promise,可以使用then函數(shù)串聯(lián)多個(gè)promise,實(shí)現(xiàn)串行執(zhí)行。

const requestAry = [() => api.request1(), () => api.request2(), () => api.request3()];
const finallyPromise = requestAry.reduce(
     (currentPromise, nextRequest) => currentPromise.then(() => nextRequest()),
     Promise.resolve() // Create an initial promise for linking promises in the array
);

2. 在新的 Promise 范圍之外更改狀態(tài)

假設(shè)你有多個(gè)頁(yè)面,其功能要求在允許使用之前收集用戶信息。點(diǎn)擊使用某個(gè)功能之前,會(huì)彈出一個(gè)彈框進(jìn)行信息收集。你會(huì)如何實(shí)施這個(gè)?

以下是不同級(jí)別前端同學(xué)的實(shí)現(xiàn)思路:

初級(jí)前端:我寫一個(gè)模態(tài)框,然后復(fù)制粘貼到其他頁(yè)面。效率非常高!

中級(jí)前端:這個(gè)不好維護(hù)。我們需要單獨(dú)封裝這個(gè)組件,并在需要的頁(yè)面引入!

高級(jí)前端:安裝任何密封的東西?。。“逊椒ㄕ{(diào)用寫在所有頁(yè)面都可以調(diào)用的地方不是更好嗎?

想要了解高級(jí)前端是如何實(shí)現(xiàn)的,以vue3為例,看一下下面的例子。

<!-- App.vue -->
<template>
<!-- The following is the modal box component -->
   <div class="modal" v-show="visible">
     <div>
       User name: <input v-model="info.name" />
     </div>
     <!-- Other information -->
     <button @click="handleCancel">Cancel</button>
     <button @click="handleConfirm">Submit</button>
   </div>
   <!-- Page components -->
</template>
<script setup>
import { provide } from 'vue';
const visible = ref(false);
const info = reactive({
   name: ''
});
let resolveFn, rejectFn;
// Pass the information collection function to the following
provide('getInfoByModal', () => {
   visible.value = true;
   return new Promise((resolve, reject) => {
     // Assign the two functions to the outside and break through the promise scope
     resolveFn = resolve;
     rejectFn = reject;
   });
})
const handleConfirm = () => {
   resolveFn && resolveFn(info);
};
const handleCancel = () => {
   rejectFn && rejectFn(new Error('User has canceled'));
};
</script>

接下來(lái),getInfoByModal就可以通過(guò)直接調(diào)用模態(tài)框來(lái)輕松獲取用戶填寫的數(shù)據(jù)。

<template>
   <button @click="handleClick">Fill in the information</button>
</template>


<script setup>
import { inject } from 'vue';
const getInfoByModal = inject('getInfoByModal');
const handleClick = async () => {
   // After the call, the modal box will be displayed. After the user clicks to confirm, the promise will be changed to the fullfilled state to obtain the user information.
   const info = await getInfoByModal();
   await api.submitInfo(info);
}
</script>

這也是很多UI組件庫(kù)中封裝常用組件的一種方式。

3. async/await 的替代用法

很多人只知道它是用來(lái)在調(diào)用await時(shí)接收async函數(shù)的返回值的,卻不知道async函數(shù)它實(shí)際上是一個(gè)返回promise的函數(shù)。例如,以下兩個(gè)函數(shù)是等效的:

const fn1 = async () => 1;
const fn2 = () => Promise.resolve(1);


fn1(); // Also returns a promise object with a value of 1

在大多數(shù)情況下,await 會(huì)跟隨 Promise 對(duì)象并等待它完全填充。因此,下面的 fn1 函數(shù) wait 也是等價(jià)的:

await fn1();


const promiseInst = fn1();
await promiseInst;

然而,await也有一個(gè)鮮為人知的秘密。當(dāng)它后面跟的值不是promise對(duì)象時(shí),它會(huì)用promise對(duì)象包裝該值,所以await后面的代碼必須異步執(zhí)行。例子:

Promise.resolve().then(() => {
  console.log(1);
});
await 2;
console.log(2);
//Print order bits: 1 2

相當(dāng)于

Promise.resolve().then(() => {
  console.log(1);
});
Promise.resolve().then(() => {
  console.log(2);
});

4. 承諾實(shí)施請(qǐng)求共享

當(dāng)一個(gè)請(qǐng)求已經(jīng)發(fā)出但尚未得到響應(yīng)時(shí),再次發(fā)出相同的請(qǐng)求,就會(huì)造成請(qǐng)求的浪費(fèi)。此時(shí),我們可以將第一個(gè)請(qǐng)求的響應(yīng)與第二個(gè)請(qǐng)求共享。

request('GET', '/test-api').then(response1 => {
  // ...
});
request('GET', '/test-api').then(response2 => {
  // ...
});

上述兩個(gè)請(qǐng)求實(shí)際上只發(fā)送一次,同時(shí)收到相同的響應(yīng)值。

那么,請(qǐng)求共享有哪些使用場(chǎng)景呢?我認(rèn)為有以下三個(gè):

  • 當(dāng)頁(yè)面渲染多個(gè)內(nèi)部組件同時(shí)獲取數(shù)據(jù)時(shí);
  • 提交按鈕未禁用且用戶連續(xù)多次點(diǎn)擊提交按鈕;
  • 預(yù)加載數(shù)據(jù)的情況下,預(yù)加載完成之前進(jìn)入預(yù)加載頁(yè)面;

這也是alova的高級(jí)功能之一。要實(shí)現(xiàn)請(qǐng)求共享,需要使用promise的緩存功能,即一個(gè)promise對(duì)象可以通過(guò)多次await獲取數(shù)據(jù)。簡(jiǎn)單的實(shí)現(xiàn)思路如下:

const pendingPromises = {};
function request(type, url, data) {
   // Use the request information as the only request key to cache the promise object being requested
   //Requests with the same key will reuse promise
   const requestKey = JSON.stringify([type, url, data]);
   if (pendingPromises[requestKey]) {
     return pendingPromises[requestKey];
   }
   const fetchPromise = fetch(url, {
     method: type,
     data: JSON.stringify(data)
   })
   .then(response => response.json())
   .finally(() => {
     delete pendingPromises[requestKey];
   });
   return pendingPromises[requestKey] = fetchPromise;
}

上述兩個(gè)請(qǐng)求實(shí)際上只發(fā)送一次,同時(shí)收到相同的響應(yīng)值。

那么,請(qǐng)求共享有哪些使用場(chǎng)景呢?我認(rèn)為有以下三個(gè):

  • 當(dāng)頁(yè)面渲染多個(gè)內(nèi)部組件同時(shí)獲取數(shù)據(jù)時(shí);
  • 提交按鈕未禁用且用戶連續(xù)多次點(diǎn)擊提交按鈕;
  • 預(yù)加載數(shù)據(jù)的情況下,預(yù)加載完成之前進(jìn)入預(yù)加載頁(yè)面;

這也是alova的高級(jí)功能之一。要實(shí)現(xiàn)請(qǐng)求共享,需要使用promise的緩存功能,即一個(gè)promise對(duì)象可以通過(guò)多次await獲取數(shù)據(jù)。簡(jiǎn)單的實(shí)現(xiàn)思路如下:

const promise = new Promise((resolve, reject) => {
  resolve();
  reject();
});

正確答案是已滿狀態(tài)。我們只需要記住,一旦待處理的promise從一種狀態(tài)轉(zhuǎn)移到另一種狀態(tài),就無(wú)法更改。因此,例子中是先轉(zhuǎn)為fulfilled狀態(tài),然后reject()就不會(huì)再轉(zhuǎn)為rejected狀態(tài)。

6.徹底明確then/catch/finally返回值

一句話概括就是,上面三個(gè)函數(shù)都會(huì)返回一個(gè)新的promise包裝對(duì)象。包裝后的值是執(zhí)行回調(diào)函數(shù)的返回值。如果回調(diào)函數(shù)拋出錯(cuò)誤,它將包裝拒絕狀態(tài)承諾。似乎不太容易理解,我們來(lái)看一個(gè)例子:

我們可以將它們一一復(fù)制到瀏覽器控制臺(tái)并運(yùn)行它們以幫助理解。

// then function
Promise.resolve().then(() => 1); // The return value is new Promise(resolve => resolve(1))
Promise.resolve().then(() => Promise.resolve(2)); // Return new Promise(resolve => resolve(Promise.resolve(2)))
Promise.resolve().then(() => {
   throw new Error('abc')
}); // Return new Promise(resolve => resolve(Promise.reject(new Error('abc'))))
Promise.reject().then(() => 1, () => 2); // The return value is new Promise(resolve => resolve(2))


//catch function
Promise.reject().catch(() => 3); // The return value is new Promise(resolve => resolve(3))
Promise.resolve().catch(() => 4); // The return value is new Promise(resolve => resolve(promise object that calls catch))
//When the finally function returns a non-promise value, return the promise object before the finally function.
Promise.resolve().finally(() => {}); // Return Promise.resolve()
Promise.reject().finally(() => {}); // Return Promise.reject()
// When the return value of the finally function is promise, wait for the returned promise to be parsed before returning the promise object before the finally function.
Promise.resolve(5).finally(() => new Promise(res => {
   setTimeout(res, 1000);
})); // Return the Promise in pending status, which will be resolved to 5 after 1 second.
Promise.reject(6).finally(() => new Promise(res => {
   setTimeout(res, 1000);
})); // Return the Promise in the pending state, and throw the number 6 after 1 second

7、then函數(shù)的第二次回調(diào)和catch回調(diào)有什么區(qū)別?

當(dāng)請(qǐng)求發(fā)生錯(cuò)誤時(shí),會(huì)觸發(fā) Promise 的 then 的第二個(gè)回調(diào)函數(shù)和 catch。乍一看沒有區(qū)別,但實(shí)際上前者無(wú)法捕獲then當(dāng)前第一個(gè)回調(diào)函數(shù)中拋出的錯(cuò)誤,但catch可以。

Promise.resolve().then(
   () => {
     throw new Error('Error from success callback');
   },
   () => {
     // will not be executed
   }
).catch(reason => {
   console.log(reason.message); // Will print out "error from success callback"
});

原理就如上一點(diǎn)所說(shuō)的。catch 函數(shù)是在 then 函數(shù)返回的處于拒絕狀態(tài)的 Promise 上調(diào)用的,因此它的錯(cuò)誤自然可以被捕獲。

8.(最終)Promise實(shí)現(xiàn)koa2洋蔥中間件模型

koa2框架引入了洋蔥模型,可以讓你的請(qǐng)求像剝洋蔥一樣一層層進(jìn)去,再一層層出來(lái),從而實(shí)現(xiàn)請(qǐng)求前后處理的統(tǒng)一。

圖片

我們來(lái)看一個(gè)簡(jiǎn)單的 koa2 洋蔥模型:

const app = new Koa();
app.use(async (ctx, next) => {
  console.log('a-start');
  await next();
  console.log('a-end');
});
app.use(async (ctx, next) => {
  console.log('b-start');
  await next();
  console.log('b-end');
});


app.listen(3000);

上面的輸出是a-start -> b-start -> b-end -> a-end,這樣神奇的輸出序列是如何實(shí)現(xiàn)的呢?有人沒天賦,簡(jiǎn)單的用20行左右的代碼就實(shí)現(xiàn)了。如有雷同,純屬巧合。

接下來(lái)我們分析一下

注:以下內(nèi)容對(duì)新手不友好,請(qǐng)謹(jǐn)慎閱讀。

首先先保存中間件函數(shù),在listen函數(shù)中收到請(qǐng)求后調(diào)用洋蔥模型執(zhí)行。

function action(koaInstance, ctx) {
  // ...
}


class Koa {
   middlewares = [];
   use(mid) {
     this.middlewares.push(mid);
   }
   listen(port) {
     // Pseudocode simulates receiving request
     http.on('request', ctx => {
       action(this, ctx);
     });
   }
}

收到請(qǐng)求后,從第一個(gè)中間件開始串行執(zhí)行next之前的前置邏輯。

//Start to start middleware call
function action(koaInstance, ctx) {
   let nextMiddlewareIndex = 1; // Identifies the next middleware index to be executed


   //Define next function
   function next() {
     // Before peeling the onion, calling next will call the next middleware function
     const nextMiddleware = middlewares[nextMiddlewareIndex];
     if (nextMiddleware) {
       nextMiddlewareIndex++;
       nextMiddleware(ctx, next);
     }
   }
   //Start execution from the first middleware function and pass in the ctx and next functions
   middlewares[0](ctx, next);
}

處理next之后的post邏輯

function action(koaInstance, ctx) {
   let nextMiddlewareIndex = 1;
   function next() {
     const nextMiddleware = middlewares[nextMiddlewareIndex];
     if (nextMiddleware) {
       nextMiddlewareIndex++;
       // A return is also added here to allow the execution of the middleware function to be executed in series from back to front using promises (it is recommended to understand this return repeatedly)
       return Promise.resolve(nextMiddleware(ctx, next));
     } else {
       // When the pre-logic of the last middleware is executed, return the fullyfilled promise and start executing the post-logic after next.
       return Promise.resolve();
     }
   }
   middlewares[0](ctx, next);
}

至此,一個(gè)簡(jiǎn)單的洋蔥模型就已經(jīng)實(shí)現(xiàn)了。

責(zé)任編輯:武曉燕 來(lái)源: 前端之神
相關(guān)推薦

2025-02-07 15:01:49

Promise數(shù)組前端

2024-01-02 16:16:34

Promise前端

2024-07-02 09:03:48

2012-10-29 11:01:17

2025-02-10 10:38:24

2022-12-15 16:38:17

2025-01-02 15:08:36

SpringBoot自動(dòng)配置Java

2010-08-25 11:14:05

云安全數(shù)據(jù)安全網(wǎng)絡(luò)安全

2022-05-30 00:04:16

開源Github技巧

2023-10-24 09:25:23

IT技巧文化

2024-04-01 07:51:49

Exclude?工具類型TypeScript

2023-06-27 09:21:33

2025-05-09 09:26:12

2024-03-21 09:58:27

ExtractTypeScript工具類型

2021-01-11 08:30:02

Dubbo服務(wù)

2023-02-22 14:50:59

技術(shù)AI

2011-09-25 10:46:18

云計(jì)算安全

2010-09-09 13:44:06

DIVCSS

2010-08-11 16:43:05

職場(chǎng)

2023-01-03 11:47:47

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 99精品视频在线观看免费播放 | 看片网站在线 | 欧美一级在线观看 | 国产午夜一级 | 国产亚洲一区二区三区在线观看 | 国产网站在线免费观看 | 日韩视频免费看 | 男插女下体视频 | av一区二区三区四区 | 国产在线观看免费 | 雨宫琴音一区二区在线 | 国产在线一级片 | 日本精品国产 | 成人精品 | 黑人精品欧美一区二区蜜桃 | 亚洲天堂久久 | 欧美成人激情 | 美女在线国产 | 亚洲激情自拍偷拍 | 欧美日日| 中文字幕视频在线看5 | 亚洲精品久久久久久久久久久久久 | 欧美日韩亚洲一区 | 免费在线视频a | 亚洲精品www | 欧美8一10sex性hd | 欧美亚洲综合久久 | 狠狠干天天干 | 四虎影院免费在线 | 视频一区在线 | 国产精品性做久久久久久 | 久久i| 成人精品一区二区三区中文字幕 | 日韩在线观看一区二区三区 | 精品美女久久久 | 精品国产一区二区在线 | 91大神在线资源观看无广告 | 久草新在线 | 国产精品永久 | 久草欧美视频 | 欧美精品a∨在线观看不卡 国产精品久久国产精品 |