在JavaScript中,Promise是一种用于异步编程的构造函数,它提供了更好的处理异步操作的方式,相较于传统的回调函数更易于管理和避免回调地狱。Promise有三种状态:Pending(进行中)、Resolved(已完成)、Rejected(已失败)。
以下是Promise的一些常见用法:
-
Promise构造函数
new Promise((resolve, reject) => {// 异步操作if (/* 成功条件 */) {resolve(value); // 当异步操作成功时,调用resolve函数,将Promise的状态变为Resolved,并传递结果值} else if (/* 失败条件 */) {reject(error); // 当异步操作失败时,调用reject函数,将Promise的状态变为Rejected,并传递错误原因} });
-
resolve()
resolve
是Promise构造函数传入的函数之一,当你确定异步操作成功时调用它,使Promise状态变为Resolved,并传递成功的值给后续的.then
或.catch
链中的回调函数。
-
Promise.race()
Promise.race(iterable)
方法接受一个Promise对象的可迭代集合(如数组),只要这个集合中的任何一个Promise变为Resolved或Rejected状态,Promise.race
就会返回的那个率先改变状态的Promise的结果(无论是Resolved还是Rejected)。
let p1 = fetch('url1'); let p2 = fetch('url2');Promise.race([p1, p2]).then(response => {// 第一个fetch请求完成后的响应 }, error => {// 第一个fetch请求抛出的错误 });
-
Promise.all()
Promise.all(iterable)
方法则是等待可迭代集合中的所有Promise全部变为Resolved状态,然后返回一个新的Promise,这个Promise在所有输入的Promise都变为Resolved时才会变为Resolved,并且它的结果是一个数组,包含了所有输入Promise的结果。
let p1 = fetch('url1'); let p2 = fetch('url2');Promise.all([p1, p2]).then(responses => {// responses是一个数组,包含了两个fetch请求的结果 }, error => {// 如果任何一个fetch请求失败了,这里的error将是第一个失败的请求的错误 });
-
.then() 和 .catch()
promise.then(onFulfilled, onRejected)
方法用于指定Promise成功或失败后的回调函数,onFulfilled
会在Promise被resolve时调用,onRejected
会在Promise被reject时调用。promise.catch(onRejected)
专门用于处理Promise失败的情况,相当于.then(null, onRejected)
。
通过这些API,开发人员可以方便地处理异步流程控制,形成更加清晰和易于维护的代码。
async function runParallel(maxConcurrency, source, iteratorFn) {const ret = []const executing = []for (const item of source) {const p = Promise.resolve().then(() => iteratorFn(item, source))ret.push(p)if (maxConcurrency <= source.length) {const e = p.then(() => executing.splice(executing.indexOf(e), 1))executing.push(e)if (executing.length >= maxConcurrency) {await Promise.race(executing)}}}return Promise.all(ret)
}
这是一个实现了并发限制的异步函数,名为runParallel
,它接受三个参数:
maxConcurrency
:整数,表示允许同时执行的任务的最大数量。source
:可迭代对象,比如数组,其中包含一系列待处理的项。iteratorFn
:一个迭代器函数,它接受两个参数:当前正在处理的项 (item
) 和源数组 (source
),并返回一个Promise。此函数用于执行针对每一项的操作。
函数的主要逻辑如下:
- 初始化一个空数组
ret
用来存放每个任务对应的Promise。 - 初始化一个空数组
executing
用来跟踪当前正在执行的任务(即Promise)。
接着遍历source
中的每一项:
- 创建一个Promise(
p
),在其内部调用iteratorFn
函数处理当前项,并立即resolve该Promise。 - 将Promise
p
添加到结果数组ret
中。 - 如果当前已执行的任务数量(
executing.length
)小于等于最大并发数(maxConcurrency
):- 当Promise
p
完成时,通过.then()
方法从executing
数组中移除自身。 - 将Promise
p
(在其完成回调上添加了删除自身的逻辑)加入到executing
数组中。 - 如果
executing
数组长度达到了maxConcurrency
,就等待数组中任意一个Promise完成(通过Promise.race(executing)
实现)。
- 当Promise
最后,函数返回Promise.all(ret)
,这意味着它会等待所有异步任务都完成之后,才返回一个Promise,这个Promise在resolve时会带有所有任务的最终结果组成的数组。
总之,runParallel
函数是用来并发执行一系列任务的,同时控制并发任务的数量不超过给定的最大并发数maxConcurrency
。