在 JavaScript 中,许多操作都是异步的,比如发起网络请求、读取文件、定时器等。Promise 提供了一种更加结构化和易于理解的方式来处理异步操作,使得异步代码更加清晰易读,避免了回调地狱的问题。
本文我将介绍 Promise 对象上 5 个非常有用的方法,掌握这些方法之后,可以让你更好地解决工作遇到的一些异步问题。
Promise.all()
当你需要并行执行多个异步操作,并且只有当所有异步操作都成功完成时才继续执行后续代码。
const promise1 = Promise.resolve("Promise"); const promise2 = new Promise((resolve, reject) => { setTimeout(resolve, 2000, "is"); }); const promise3 = new Promise((resolve, reject) => { setTimeout(resolve, 1000, "useful"); }); Promise.all([promise1, promise2, promise3]).then((values) => { console.log(values); });
以上代码成功运行后,控制台会输出以下结果:
[ 'Promise', 'is', 'useful' ]
但如果某个 promise 对象在执行过程中抛出异常,比如,promise2 对象在执行时抛出异常:
const promise2 = new Promise((resolve, reject) => { setTimeout(reject, 2000, new Error("Crash...")); });
那么,你就无法正常获取 promise1 和 promise3 对象返回的结果。针对这个问题,你可以使用 Promise.allSettled() 方法。
Promise.allSettled()
当你想要等待多个异步操作完成,并且你需要知道每个异步操作的结果。
const promise1 = Promise.resolve("Promise"); const promise2 = new Promise((resolve, reject) => { setTimeout(reject, 2000, new Error("Crash...")); }); const promise3 = new Promise((resolve, reject) => { setTimeout(resolve, 1000, "useful"); }); Promise.allSettled([promise1, promise2, promise3]).then((values) => { console.log(values); });
运行以上代码之后,控制台会输出以下结果。数组中每个对象上的 status 属性是用于标识对应 promise 对象的执行状态。
[ { status: 'fulfilled', value: 'Promise' }, { status: 'rejected', reason: Error: Crash... }, { status: 'fulfilled', value: 'useful' } ]
Promise.race()
当你有多个异步操作,并且你只关心哪个操作最先完成,不管它是成功还是失败。
const promise1 = new Promise((resolve, reject) => { setTimeout(reject, 1000, "Promise 1 resolved"); }); const promise2 = new Promise((resolve, reject) => { setTimeout(resolve, 2000, "Promise 2 resolved"); }); Promise.race([promise1, promise2]).then((value) => { console.log(value); });
以上代码成功运行后,控制台会输出 "Promise 1 resolved"。
Promise.any()
当你有多个异步操作,并且你想要得到第一个成功的异步操作的结果,而忽略其他已失败的异步操作。
const promise1 = Promise.reject("any"); const promise2 = new Promise((resolve) => setTimeout(resolve, 100, "Promise 2 resolved") ); const promise3 = new Promise((resolve) => setTimeout(resolve, 500, "Promise 3 resolved") ); Promise.any([promise1, promise2, promise3]).then((value) => { console.log(value); });
以上代码成功运行后,控制台会输出 "Promise 2 resolved"。
Promise.withResolvers()
在某些场景下,我们希望在外部控制 Promise 对象的状态。比如,在请求网络数据的场景,当成功接收所有数据后,才调用 resolve 方法设置当前 Promise 的返回数据。
let resolve, reject; const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); asyncRequest(config, response => { const buffer = []; response.on('callback-request', id => { promise.then(data => callback(id, data)); }); response.on('data', data => buffer.push(data)); response.on('end', () => resolve(buffer)); response.on('error', reason => reject(reason)); });
上述的场景在日常工作中很常见,为了避免重复写以下代码。
let resolve, reject; const promise = new Promise((res, rej) => { resolve = res; reject = rej; });
ts39 增加了 proposal-promise-with-resolvers 草案,目前该草案的状态已经是 Stage 4。不过在使用的过程中,需要注意它的兼容性:
对于不支持 Promise.withResolvers() 方法的环境,我们可以通过通过自定义函数来实现对应的功能。比如,TypeScript 源码中,定义了一个 defer 函数来实现 Promise.withResolvers() 方法同样的功能。
export function defer<T = void>(): Deferred<T> { let resolve!: (value: T | PromiseLike<T>) => void; let reject!: (reason: unknown) => void; const promise = new Promise<T>((_resolve, _reject) => { resolve = _resolve; reject = _reject; }); return { resolve, reject, promise }; }
原文地址:https://mp.weixin.qq.com/s/gri-8ClxnLZGFBpOA6FoLw