JavaScript中你不得不知道的Promise高級(jí)用法分享
在JavaScript中,Promise是一種解決異步編程問(wèn)題的重要方式。一個(gè)Promise對(duì)象代表了一個(gè)將要在本次操作完成后立即、稍后或從未實(shí)現(xiàn)的返回值。以下是23個(gè)高級(jí)用法的探討,每一個(gè)都在JavaScript的海洋中航行,讓開(kāi)發(fā)者們能夠以更高效、優(yōu)雅的方式處理異步操作。
1. 并發(fā)控制
使用Promise.all
可以并行執(zhí)行多個(gè)Promise,但當(dāng)需要控制并發(fā)的請(qǐng)求數(shù)量時(shí),可以通過(guò)實(shí)現(xiàn)一個(gè)并發(fā)控制函數(shù)來(lái)控制同時(shí)執(zhí)行的Promise數(shù)量。
const concurrentPromises = (promises, limit) => { return new Promise((resolve, reject) => { let i = 0; let result = []; const executor = () => { if (i >= promises.length) { return resolve(result); } const promise = promises[i++]; Promise.resolve(promise) .then(value => { result.push(value); if (i < promises.length) { executor(); } else { resolve(result); } }) .catch(reject); }; for (let j = 0; j < limit && j < promises.length; j++) { executor(); } }); };
2. Promise超時(shí)
有時(shí)候,我們希望Promise在一定時(shí)間內(nèi)如果沒(méi)有得到解決就自動(dòng)reject。這可以用下面的方式實(shí)現(xiàn)。
const promiseWithTimeout = (promise, ms) => Promise.race([ promise, new Promise((resolve, reject) => setTimeout(() => reject(new Error('Timeout after ' + ms + 'ms')), ms) ) ]);
3. Promise的取消
JavaScript原生的Promise是無(wú)法取消的,但我們可以通過(guò)引入一個(gè)可控的中斷邏輯來(lái)模擬取消Promise。
const cancellablePromise = promise => { let isCanceled = false; const wrappedPromise = new Promise((resolve, reject) => { promise.then( value => (isCanceled ? reject({ isCanceled, value }) : resolve(value)), error => (isCanceled ? reject({ isCanceled, error }) : reject(error)) ); }); return { promise: wrappedPromise, cancel() { isCanceled = true; } }; };
4. 檢測(cè)Promise狀態(tài)
原生的Promise不允許直接查詢(xún)狀態(tài)。但可以通過(guò)一定的技巧來(lái)了解當(dāng)前Promise是否已解決、被拒絕或尚未解決。
const reflectPromise = promise => promise.then( value => ({ status: 'fulfilled', value }), error => ({ status: 'rejected', error }) );
5. 順序執(zhí)行Promise數(shù)組
有時(shí)候我們需要按順序執(zhí)行一組Promise,以確保前一個(gè)異步操作完成后再開(kāi)始下一個(gè)。
const sequencePromises = promises => promises.reduce( (prev, next) => prev.then(() => next()), Promise.resolve() );
6. 基于條件的Promise鏈
在某些場(chǎng)合下,需要根據(jù)條件判斷是否執(zhí)行下一個(gè)Promise。
const conditionalPromise = (conditionFn, promise) => conditionFn() ? promise : Promise.resolve();
7. Promise的重試邏輯
當(dāng)Promise因?yàn)槟承簳r(shí)性的錯(cuò)誤被拒絕時(shí),可能希望能夠重試執(zhí)行。
const retryPromise = (promiseFn, maxAttempts, interval) => { return new Promise((resolve, reject) => { const attempt = attemptNumber => { if (attemptNumber === maxAttempts) { reject(new Error('Max attempts reached')); return; } promiseFn().then(resolve).catch(() => { setTimeout(() => { attempt(attemptNumber + 1); }, interval); }); }; attempt(0); }); };
8. 確保Promise只解決一次
在某些情況下,可能希望確保Promise只會(huì)解決一次,即使可能會(huì)被多次調(diào)用resolve
。
const onceResolvedPromise = executor => { let isResolved = false; return new Promise((resolve, reject) => { executor( value => { if (!isResolved) { isResolved = true; resolve(value); } }, reject ); }); };
9. 使用Promise.allSettled處理多個(gè)異步操作
與Promise.all
不同的是,Promise.allSettled
會(huì)等到所有的prromise都結(jié)束后才完成,無(wú)論每個(gè)promise結(jié)束后是fulfilled還是rejected。
const promises = [fetch('/api/endpoint1'), fetch('/api/endpoint2')]; Promise.allSettled(promises).then(results => { results.forEach((result, index) => { if (result.status === 'fulfilled') { console.log(`Promise ${index + 1} succeeded with value ${result.value}`); } else { console.error(`Promise ${index + 1} failed with reason ${result.reason}`); } }); });
10. 處理多個(gè)Promises的最快響應(yīng)
當(dāng)處理多個(gè)異步請(qǐng)求,而只關(guān)心最快回應(yīng)的結(jié)果時(shí),可以使用Promise.race
來(lái)實(shí)現(xiàn)。
const promises = [fetch('/api/endpointA'), fetch('/api/endpointB')]; Promise.race(promises) .then(value => { // 處理最快的響應(yīng) }) .catch(reason => { // 處理最早的拒絕 });
11. 使用async/await簡(jiǎn)化Promise
async
和await
關(guān)鍵字可以讓異步代碼看起來(lái)更像同步代碼,使得邏輯更清晰。
async function asyncFunction() { try { const result = await aPromise; // Do something with result } catch (error) { // Handle error } }
12. 連續(xù)獲取不確定數(shù)量的數(shù)據(jù)頁(yè)
當(dāng)獲取分頁(yè)數(shù)據(jù)時(shí),我們可能不知道一共有多少頁(yè),可以采取遞歸的方式直到取完所有頁(yè)。
async function fetchPages(apiEndpoint, page = 1, allResults = []) { const response = await fetch(`${apiEndpoint}?page=${page}`); const data = await response.json(); if (data.nextPage) { return fetchPages(apiEndpoint, page + 1, allResults.concat(data.results)); } else { return allResults.concat(data.results); } }
13. 映射并發(fā)Promises并處理結(jié)果數(shù)組
當(dāng)需要并發(fā)執(zhí)行異步函數(shù)并處理所有結(jié)果時(shí),可以使用Promise.all
。
const fetchUrls = urls => { const fetchPromises = urls.map(url => fetch(url).then(response => response.json())); return Promise.all(fetchPromises); };
14. 使用Generators管理流程
通過(guò)將async/await
與Generators配合,可以創(chuàng)建一個(gè)可控制的異步流程管理器。
function* asyncGenerator() { const result1 = yield aPromise1; const result2 = yield aPromise2(result1); // ... }
15. 使用Promises替代回調(diào)
Promise提供了一種更標(biāo)準(zhǔn)和便捷的方式來(lái)處理異步操作,將回調(diào)函數(shù)替換為Promise。
const callbackToPromise = (fn, ...args) => { return new Promise((resolve, reject) => { fn(...args, (error, result) => { if (error) { reject(error); } else { resolve(result); } }); }); };
16. 流式處理大型數(shù)據(jù)集
使用Promise處理大型數(shù)據(jù)集時(shí),最好是流式地獲取和處理這些數(shù)據(jù),以避免內(nèi)存過(guò)載。
async function processLargeDataSet(dataSet) { for (const dataChunk of dataSet) { const processedChunk = await process(dataChunk); // Returns a Promise await save(processedChunk); // Another async operation } }
17. 同時(shí)執(zhí)行多個(gè)異步任務(wù)并處理中途的失敗
有時(shí)即便其中一個(gè)異步任務(wù)失敗了,也希望其他任務(wù)能夠順利完成。
const promises = [promise1, promise2, promise3]; Promise.all(promises.map(reflectPromise)).then(results => { results.forEach(result => { if (result.status === 'fulfilled') { // Do something with result.value } else { // Handle result.error } }); });
18. Promise-pipeline
通過(guò)管道化promise可以依次執(zhí)行一系列異步操作。
const promisePipe = (...fns) => value => fns.reduce((p, f) => p.then(f), Promise.resolve(value));
19. 使用promise實(shí)現(xiàn)一個(gè)延時(shí)
可以使用Promise結(jié)合setTimeout來(lái)實(shí)現(xiàn)一個(gè)異步的延時(shí)函數(shù)。
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
20. 動(dòng)態(tài)生成Promise鏈
在一些情況下,可能需要根據(jù)不同條件動(dòng)態(tài)生成一系列的Promise鏈。
const tasks = [task1, task2, task3]; // Array of asynchronous tasks const promiseChain = tasks.reduce((chain, currentTask) => { return chain.then(currentTask); }, Promise.resolve());
21. 使用Promise實(shí)現(xiàn)簡(jiǎn)易的異步鎖
在多線(xiàn)程環(huán)境中,可以使用Promise來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)易的異步鎖。
let lock = Promise.resolve(); const acquireLock = () => { let release; const waitLock = new Promise(resolve => { release = resolve; }); const tryAcquireLock = lock.then(() => release); lock = waitLock; return tryAcquireLock; };
22. 組合多個(gè)Promise操作為一個(gè)函數(shù)
可以將多個(gè)Promise操作合并為一個(gè)函數(shù),通過(guò)函數(shù)復(fù)用減少冗余代碼。
const fetchDataAndProcess = async url => { const data = await fetch(url).then(resp => resp.json()); return processData(data); };
23. 處理可選的異步操作
有些場(chǎng)合下,一個(gè)異步操作是可選的,可以使用下面的方式來(lái)處理。
async function optionallyAsyncTask(condition, asyncOperation, fallbackValue) { if (condition) { return await asyncOperation; } else { return fallbackValue; } }
結(jié)語(yǔ)
Promise是現(xiàn)代JavaScript異步編程不可或缺的一部分,精通其高級(jí)技巧將大大提升開(kāi)發(fā)效率和代碼質(zhì)量。通過(guò)上面介紹的多種用法,開(kāi)發(fā)者們可以更自信地處理各種復(fù)雜的異步場(chǎng)景,并能夠?qū)懗龈勺x、更優(yōu)雅、更健壯的代碼。
以上就是JavaScript中你不得不知道的Promise高級(jí)用法分享的詳細(xì)內(nèi)容,更多關(guān)于JavaScript Promise的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于js實(shí)現(xiàn)復(fù)制內(nèi)容到操作系統(tǒng)粘貼板過(guò)程解析
這篇文章主要介紹了基于js實(shí)現(xiàn)復(fù)制內(nèi)容到操作系統(tǒng)粘貼板過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10JavaScript實(shí)現(xiàn)圖片無(wú)縫滾動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)圖片無(wú)縫滾動(dòng)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07moment.js 計(jì)算當(dāng)前一周、一月對(duì)應(yīng)日期的實(shí)例
這篇文章主要介紹了moment.js 計(jì)算當(dāng)前一周、一月對(duì)應(yīng)日期的實(shí)例代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12QT與javascript交互數(shù)據(jù)的實(shí)現(xiàn)
本文主要介紹了QT與javascript交互數(shù)據(jù)的實(shí)現(xiàn),主要包括數(shù)據(jù)從QT流向JS以及數(shù)據(jù)從JS流向QT的幾種方法,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05JavaScript實(shí)現(xiàn)的貝塞爾曲線(xiàn)算法簡(jiǎn)單示例
這篇文章主要介紹了JavaScript實(shí)現(xiàn)的貝塞爾曲線(xiàn)算法,結(jié)合簡(jiǎn)單實(shí)例形式分析了基于javascript的貝塞爾曲線(xiàn)算法的相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2018-01-01微信小程序?qū)崿F(xiàn)手機(jī)獲取驗(yàn)證碼倒計(jì)時(shí)60s
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)手機(jī)獲取驗(yàn)證碼后倒計(jì)時(shí)60s,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05