你必须要知道的,五个Promise高级使用技巧

开发 前端
无论是在开发中还是在面试中 promise 都是一个非常重要的内容。常见的面试中都会问及到 promise.then()、Promise.all 或者配合 async/await 使用的方式。

无论是在开发中还是在面试中 promise 都是一个非常重要的内容。常见的面试中都会问及到 promise.then()、Promise.all 或者配合 async/await 使用的方式。

但是,一旦我们遇到更高级别的岗位(比如大厂高P岗位),那么以上这些知识可能就不够使用了。所以说,咱们今天就来分享 5个promise的“高级”使用技巧,提高对 promise 的理解,帮大家通过高P面试!

技巧 1:Promise 顺序执行

当面对必须顺序执行一系列任务的场景时,我们第一时间都会想到 “await”。但是除了 await 之外,使用 Promise 的替代方法可能更加优雅。

const requestAry = [() => api.request1(), () => api.request2(), () => api.request3()];
// 使用 `await`
for (const requestItem of requestAry) {
 await requestItem();
}
// 使用promise进行串行执行
const finallyPromise = requestAry.reduce(
 (currentPromise, nextRequest) => currentPromise.then(() => nextRequest()),
 Promise.resolve() 
);

该方法使用“then”函数,可以简洁高效地连接 Promise,确保任务的串行执行。

技巧 2: Async/Await 的替代用法

使用 async/await 作为接收异步函数返回值的这种方式大家应该都比较熟悉,但很少有人认识到异步函数从根本上来说是返回一个 promise。

我们来看下面这个场景

const fn1 = async () => 1;
const fn2 = () => Promise.resolve(1);
fn1(); // 返回值为1的promise对象

通常,await 与 Promise 对象一起使用,等待 promise 被解析。 因此,等待 fn1 函数也相当于以下内容:

await fn1();
-----
const promiseInst = fn1();
await promiseInst;

但是,对于 await 大家需要知道:当后面的值不是 Promise 对象时,它将会把该值包装在 Promise 对象中。 因此,await之后的代码必须异步执行:

Promise.resolve().then(() => {
 console.log(1);
});
await 2;
console.log(2);
// 输出: 1 2

这相当于:

Promise.resolve().then(() => {
 console.log(1);
});
Promise.resolve().then(() => {
 console.log(2);
});

技巧 3:promise 处理连续的请求

当先前的请求仍处于 待处理状态 时发送重复的请求可能会导致不必要的资源消耗。

request('GET', '/test-api').then(response1 => {
 // …
});
request('GET', '/test-api').then(response2 => {
 // …
});

并且这种场景非常常见:

  • 在页面上渲染多个内部组件同时获取数据时。
  • 处理提交按钮未禁用,用户连续点击多次的场景。
  • 预加载数据时,在预加载完成前导航至预加载页面。

所以,我们可以对 promise 进行对应的封装处理,利用 缓存策略 解决这个问题,可以参考以下代码:

// 缓存对象
const pendingPromises = {};
function request(type, url, data) {
   const requestKey = JSON.stringify([type, url, data]);
   // 读取缓存
   if (pendingPromises[requestKey]) {
     return pendingPromises[requestKey];
   }
  const fetchPromise = fetch(url, {
     method: type,
     data: JSON.stringify(data)
  })
   .then(response => response.json())
   .finally(() => {
     delete pendingPromises[requestKey];
   });
   // 存入缓存
  return pendingPromises[requestKey] = fetchPromise;
}

技巧 4:解码 then/catch/finally 返回值

我们知道 promise 拥有三种状态的返回值:

.then 处理

// 返回新的 Promise(resolve => resolve(1))
Promise.resolve().then(() => 1); 
// 返回新的 Promise(resolve => resolve(Promise.resolve(2)))
Promise.resolve().then(() => Promise.resolve(2)); 
// 返回新的 Promise(resolve => resolve(Promise.reject(new Error('abc'))))
Promise.resolve().then(() => { throw new Error('abc') }); 
// 返回新的 Promise(resolve => resolve(2))
Promise.reject().then(() => 1, () => 2);

.catch 处理

// 返回新的 Promise(resolve => resolve(3))
Promise.reject().catch(() => 3); 
// 返回新的 Promise(resolve => resolve(promise object calling catch))
Promise.resolve().catch(() => 4);

.finally 处理

  • 当finally函数返回非promise值时,它会在finally函数之前返回promise对象。
// 返回 Promise.resolve()
Promise.resolve().finally(() => {}); 
// 返回 Promise.reject()
Promise.reject().finally(() => {});
  • 当finally函数的返回值是一个promise时,它会在finally函数之前等待promise解析,然后再返回promise对象。
// 返回处于 pending 状态下的 Promise, 1秒后 resolve 为 5。
Promise.resolve(5).finally(() => new Promise(res => {
 setTimeout(res, 1000);
})); 
Promise.reject(6).finally(() => new Promise(res => {
 setTimeout(res, 1000);
})); // 返回处于 pending 状态下的 Promise, 在1秒后 reject 为 6。

技巧 5:区分“then”的第二个回调和“catch”回调

promise 有两种处理错误的方式,分别是:

  • .then 的第二个参数回调函数
  • .catch 回调

当请求出现错误时,第二个回调函数和 Promise 的 .catch 都会被触发。

乍一看,它们好像没什么区别,但是——前者(第二个参数回调函数)无法捕获“then”当前第一个回调函数中抛出的错误,而“catch”可以:

Promise.resolve().then(
 () => {
 throw new Error('成功的回调出现错误');
 },
 () => {
 // 这里不会执行
 }
).catch(reason => {
 console.log(reason.message); // 成功的回调出现错误
});
责任编辑:华轩 来源: 程序员Sunday
相关推荐

2012-04-09 13:16:20

DIVCSS

2019-08-06 14:54:22

Hadoop数据集海量数据

2018-11-28 10:00:42

React组件前端

2021-06-07 14:04:13

并发编程Future

2022-09-27 14:36:57

JavaScrip数组开发

2019-02-18 13:36:03

Redis数据库面试

2023-05-12 14:49:47

CSS框架前端

2011-07-13 11:03:17

ASP

2023-11-23 10:21:37

2020-03-27 12:30:39

python开发代码

2014-01-10 13:29:44

微软Office 365云计算

2020-04-08 17:10:03

GitHub代码开源

2013-03-04 09:34:48

CSSWeb

2023-01-09 17:23:14

CSS技巧

2024-04-03 10:29:13

JavaScrip优化技巧

2010-07-27 11:24:51

Flex

2012-10-18 16:14:56

Windows 8

2020-11-10 08:30:58

Gartner数字化技术

2022-07-06 15:51:48

浏览器开发者工具

2018-09-10 09:26:33

点赞
收藏

51CTO技术栈公众号