JavaScript中你不得不知道的Promise高級用法分享
在JavaScript中,Promise是一種解決異步編程問題的重要方式。一個Promise對象代表了一個將要在本次操作完成后立即、稍后或從未實現(xiàn)的返回值。以下是23個高級用法的探討,每一個都在JavaScript的海洋中航行,讓開發(fā)者們能夠以更高效、優(yōu)雅的方式處理異步操作。
1. 并發(fā)控制
使用Promise.all可以并行執(zhí)行多個Promise,但當需要控制并發(fā)的請求數(shù)量時,可以通過實現(xiàn)一個并發(fā)控制函數(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超時
有時候,我們希望Promise在一定時間內(nèi)如果沒有得到解決就自動reject。這可以用下面的方式實現(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是無法取消的,但我們可以通過引入一個可控的中斷邏輯來模擬取消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. 檢測Promise狀態(tài)
原生的Promise不允許直接查詢狀態(tài)。但可以通過一定的技巧來了解當前Promise是否已解決、被拒絕或尚未解決。
const reflectPromise = promise =>
promise.then(
value => ({ status: 'fulfilled', value }),
error => ({ status: 'rejected', error })
);
5. 順序執(zhí)行Promise數(shù)組
有時候我們需要按順序執(zhí)行一組Promise,以確保前一個異步操作完成后再開始下一個。
const sequencePromises = promises =>
promises.reduce(
(prev, next) => prev.then(() => next()),
Promise.resolve()
);
6. 基于條件的Promise鏈
在某些場合下,需要根據(jù)條件判斷是否執(zhí)行下一個Promise。
const conditionalPromise = (conditionFn, promise) => conditionFn() ? promise : Promise.resolve();
7. Promise的重試邏輯
當Promise因為某些暫時性的錯誤被拒絕時,可能希望能夠重試執(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只會解決一次,即使可能會被多次調(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處理多個異步操作
與Promise.all不同的是,Promise.allSettled會等到所有的prromise都結束后才完成,無論每個promise結束后是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. 處理多個Promises的最快響應
當處理多個異步請求,而只關心最快回應的結果時,可以使用Promise.race來實現(xiàn)。
const promises = [fetch('/api/endpointA'), fetch('/api/endpointB')];
Promise.race(promises)
.then(value => {
// 處理最快的響應
})
.catch(reason => {
// 處理最早的拒絕
});
11. 使用async/await簡化Promise
async和await關鍵字可以讓異步代碼看起來更像同步代碼,使得邏輯更清晰。
async function asyncFunction() {
try {
const result = await aPromise;
// Do something with result
} catch (error) {
// Handle error
}
}
12. 連續(xù)獲取不確定數(shù)量的數(shù)據(jù)頁
當獲取分頁數(shù)據(jù)時,我們可能不知道一共有多少頁,可以采取遞歸的方式直到取完所有頁。
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并處理結果數(shù)組
當需要并發(fā)執(zhí)行異步函數(shù)并處理所有結果時,可以使用Promise.all。
const fetchUrls = urls => {
const fetchPromises = urls.map(url => fetch(url).then(response => response.json()));
return Promise.all(fetchPromises);
};
14. 使用Generators管理流程
通過將async/await與Generators配合,可以創(chuàng)建一個可控制的異步流程管理器。
function* asyncGenerator() {
const result1 = yield aPromise1;
const result2 = yield aPromise2(result1);
// ...
}
15. 使用Promises替代回調(diào)
Promise提供了一種更標準和便捷的方式來處理異步操作,將回調(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ù)據(jù),以避免內(nèi)存過載。
async function processLargeDataSet(dataSet) {
for (const dataChunk of dataSet) {
const processedChunk = await process(dataChunk); // Returns a Promise
await save(processedChunk); // Another async operation
}
}
17. 同時執(zhí)行多個異步任務并處理中途的失敗
有時即便其中一個異步任務失敗了,也希望其他任務能夠順利完成。
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
通過管道化promise可以依次執(zhí)行一系列異步操作。
const promisePipe = (...fns) => value => fns.reduce((p, f) => p.then(f), Promise.resolve(value));
19. 使用promise實現(xiàn)一個延時
可以使用Promise結合setTimeout來實現(xiàn)一個異步的延時函數(shù)。
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
20. 動態(tài)生成Promise鏈
在一些情況下,可能需要根據(jù)不同條件動態(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實現(xiàn)簡易的異步鎖
在多線程環(huán)境中,可以使用Promise來實現(xià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. 組合多個Promise操作為一個函數(shù)
可以將多個Promise操作合并為一個函數(shù),通過函數(shù)復用減少冗余代碼。
const fetchDataAndProcess = async url => {
const data = await fetch(url).then(resp => resp.json());
return processData(data);
};
23. 處理可選的異步操作
有些場合下,一個異步操作是可選的,可以使用下面的方式來處理。
async function optionallyAsyncTask(condition, asyncOperation, fallbackValue) {
if (condition) {
return await asyncOperation;
} else {
return fallbackValue;
}
}
結語
Promise是現(xiàn)代JavaScript異步編程不可或缺的一部分,精通其高級技巧將大大提升開發(fā)效率和代碼質(zhì)量。通過上面介紹的多種用法,開發(fā)者們可以更自信地處理各種復雜的異步場景,并能夠?qū)懗龈勺x、更優(yōu)雅、更健壯的代碼。
以上就是JavaScript中你不得不知道的Promise高級用法分享的詳細內(nèi)容,更多關于JavaScript Promise的資料請關注腳本之家其它相關文章!
相關文章
基于js實現(xiàn)復制內(nèi)容到操作系統(tǒng)粘貼板過程解析
這篇文章主要介紹了基于js實現(xiàn)復制內(nèi)容到操作系統(tǒng)粘貼板過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-10-10
QT與javascript交互數(shù)據(jù)的實現(xiàn)
本文主要介紹了QT與javascript交互數(shù)據(jù)的實現(xiàn),主要包括數(shù)據(jù)從QT流向JS以及數(shù)據(jù)從JS流向QT的幾種方法,需要的朋友們下面隨著小編來一起學習學習吧2021-05-05
JavaScript實現(xiàn)的貝塞爾曲線算法簡單示例
這篇文章主要介紹了JavaScript實現(xiàn)的貝塞爾曲線算法,結合簡單實例形式分析了基于javascript的貝塞爾曲線算法的相關實現(xiàn)技巧,需要的朋友可以參考下2018-01-01
微信小程序?qū)崿F(xiàn)手機獲取驗證碼倒計時60s
這篇文章主要為大家詳細介紹了微信小程序?qū)崿F(xiàn)手機獲取驗證碼后倒計時60s,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-05-05

