Promise 是前端开发中常用的异步编程解决方案之一,它可以有效地解决回调地狱的问题。但是在实际开发中,我们经常需要同时发送多个请求,并发数过多可能会导致性能问题,因此控制并发数成为一项重要的优化手段。本文将详细介绍 Promise 并发数控制的实现方式和优化方法,并提供示例代码供读者参考。
Promise 并发数控制的实现方式
1. 串行执行
串行执行是最简单的实现方式,即每个 Promise 对象在前一个 Promise 对象 resolved 后再执行。这种方式的优点是简单易懂,缺点是效率较低。
function serialExecute(promises) {
return promises.reduce((prev, current) => {
return prev.then(() => current())
}, Promise.resolve())
}2. 并行执行
并行执行是最常用的实现方式,即同时执行多个 Promise 对象,直到所有的 Promise 都 resolved 或 rejected。这种方式的优点是效率高,缺点是容易导致并发数过多,影响性能。
function parallelExecute(promises) {
return Promise.all(promises.map(p => p()))
}3. 并发数控制
并发数控制是一种介于串行执行和并行执行之间的实现方式,它可以控制并发数,提高性能。具体实现方式是通过一个计数器来控制当前并发数量,当计数器小于最大并发数时,继续执行 Promise 对象;当计数器等于最大并发数时,暂停执行 Promise 对象,直到有 Promise 对象 resolved 或 rejected 后,再继续执行。
// www.javascriptcn.com code example
function limitExecute(promises, maxCount) {
let index = 0
let count = 0
let results = []
return new Promise((resolve, reject) => {
function execute() {
while (count < maxCount && index < promises.length) {
let i = index++
count++
promises[i]().then(result => {
results[i] = result
count--
if (index === promises.length && count === 0) {
resolve(results)
} else {
execute()
}
}).catch(error => {
reject(error)
})
}
}
execute()
})
}Promise 并发数控制的优化方法
1. 调整最大并发数
最大并发数的调整可以根据实际情况进行,一般建议在 5~10 之间。如果并发数过多,可能会导致浏览器卡顿或崩溃。如果并发数过少,可能会导致请求的响应时间过长。
2. 使用 Promise.allSettled
Promise.allSettled 可以同时处理多个 Promise 对象,不管是 resolved 还是 rejected,返回结果都是一个数组。这种方式可以避免因为某个 Promise 对象 rejected 而导致整个 Promise.all 被中断的问题。
// www.javascriptcn.com code example
function limitExecute(promises, maxCount) {
let index = 0
let count = 0
let results = []
return new Promise((resolve, reject) => {
function execute() {
while (count < maxCount && index < promises.length) {
let i = index++
count++
promises[i]().then(result => {
results[i] = result
}).catch(error => {
results[i] = error
}).finally(() => {
count--
if (index === promises.length && count === 0) {
resolve(results)
} else {
execute()
}
})
}
}
execute()
})
}3. 使用 async/await
async/await 是 ES2017 中新增的异步编程解决方案,它可以让异步代码看起来像同步代码,减少了回调嵌套的问题。使用 async/await 可以让代码更加简洁易懂。
// www.javascriptcn.com code example
async function limitExecute(promises, maxCount) {
let index = 0
let count = 0
let results = []
while (index < promises.length) {
while (count < maxCount && index < promises.length) {
let i = index++
count++
try {
let result = await promises[i]()
results[i] = result
} catch (error) {
results[i] = error
} finally {
count--
}
}
await new Promise(resolve => setTimeout(resolve, 0))
}
return results
}示例代码
下面是一个使用 Promise 并发数控制的示例代码,其中包含了串行执行、并行执行和并发数控制三种实现方式。
// www.javascriptcn.com code example
function fetchData(url) {
return () => {
return fetch(url).then(response => response.json())
}
}
let urls = [
'https://jsonplaceholder.typicode.com/todos/1',
'https://jsonplaceholder.typicode.com/todos/2',
'https://jsonplaceholder.typicode.com/todos/3',
'https://jsonplaceholder.typicode.com/todos/4',
'https://jsonplaceholder.typicode.com/todos/5',
'https://jsonplaceholder.typicode.com/todos/6',
'https://jsonplaceholder.typicode.com/todos/7',
'https://jsonplaceholder.typicode.com/todos/8',
'https://jsonplaceholder.typicode.com/todos/9',
'https://jsonplaceholder.typicode.com/todos/10'
]
serialExecute(urls.map(url => fetchData(url)))
.then(results => console.log('Serial:', results))
.catch(error => console.error(error))
parallelExecute(urls.map(url => fetchData(url)))
.then(results => console.log('Parallel:', results))
.catch(error => console.error(error))
limitExecute(urls.map(url => fetchData(url)), 5)
.then(results => console.log('Limit:', results))
.catch(error => console.error(error))结语
本文介绍了 Promise 并发数控制的实现方式和优化方法,并提供了示例代码供读者参考。在实际开发中,合理地控制并发数可以提高程序的性能,避免因为并发数过多而导致的性能问题。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d236c1a941bf71344340b8