在 JavaScript 中使用异步函数的更好方式

如果您从事 Web 开发,那么您百分之百至少使用过一些异步函数。使用异步函数有不同的方式,例如 .then()async/await 。但如果我告诉您还有更好的使用异步函数的方式,可以将请求时间减少多达一半,您会怎么想? 是的,这是真的!JavaScript 运行时提供了各种我们通常不知道或不使用的功能。其中一个功能是 Promise 类的静态方法。 在这篇简短的博客文章中,我们将探讨如何使用这些方法来改进我们的异步函数调用。

Promise.all()

Promise.all() 方法接受一个可迭代的承诺作为输入,并返回一个单个的承诺,该承诺解决为输入承诺的结果数组。如果任何输入承诺被拒绝,或者非承诺抛出错误,它会立即拒绝,并将以第一个拒绝方法拒绝。

下面是一个例子:

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve,reject)=>{
     setTimeout(resolve,100,'foo');
})
Promise.all([promise1,promise2,promise3]).then((values)=>{
     console.log(values);
})
// 预期输出数组 [3,42,'foo']

现在让我们看看如何使用它来加速我们的异步调用:

顺序执行与并发执行

通常,在一个接一个地进行异步函数调用时,每个请求都会被它之前的请求阻塞,这种模式也被称为“瀑布”模式,因为每个请求只有在前一个请求返回一些数据后才能开始。

顺序执行模式

// 模拟两个具有不同响应时间的 API 调用
function fetchFastData() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("Fast data");
    }, 2000);
  });
}
​
function fetchSlowData() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("Slow data");
    }, 3000);
  });
}
​
​
// 演示顺序执行的函数
async function fetchDataSequentially() {
  console.log("开始获取数据...");
​
  const startTime = Date.now();
​
  // 同时开始两个获取
  const fastData = await fetchFastData();
  const slowData = await fetchSlowData();
​
  const endTime = Date.now();
  const totalTime = endTime - startTime;
​
  console.log(`快速数据: ${fastData}`);
  console.log(`慢速数据: ${slowData}`);
  console.log(`总耗时: ${totalTime}ms`);
}
fetchDataSequentially()
/*
预期输出:
开始获取数据...
快速数据: Fast data
慢速数据: Slow data
总耗时: 5007ms
*/

这里有一个图表以便更好地可视化

使用 Promise.all() ,我们可以一次性触发所有请求,然后等待它们全部完成,这样,由于请求不必等待前一个完成就可以提前开始,因此可以更早地解决。Promise.all() 一旦传递给它的所有承诺都解决,就会返回一个包含已解决承诺的数组。 下面是如何使用承诺来改进我们的 fetchData 函数。

并发执行模式

async function fetchDataConcurrently() {
  console.log("开始获取数据...");
​
  const startTime = Date.now();
​
  // 同时开始两个获取
  const fastDataPromise =  fetchFastData();
  const slowDataPromise =  fetchSlowData();
​
  // 等待两个承诺都解决
  const [fastData, slowData] = await Promise.all([fastDataPromise, slowDataPromise]);
​
  const endTime = Date.now();
  const totalTime = endTime - startTime;
​
  console.log(`快速数据: ${fastData}`);
  console.log(`慢速数据: ${slowData}`);
  console.log(`总耗时: ${totalTime}ms`);
}
/*
预期输出:
开始获取数据...
快速数据: Fast data
慢速数据: Slow data
总耗时: 3007ms
*/

这里有一个图表以便更好地可视化

我们将所有的承诺放在一个数组中传递给 Promise.all() ,然后等待它。如果有多个请求,我们可以通过这种方式节省大量时间。

不过有一件事需要考虑:如果一个承诺被拒绝了怎么办?如果在这种情况下我们使用 Promise.all() ,它只会因被拒绝的承诺而拒绝。如果我们想要得到所有承诺的结果,无论是解决还是拒绝呢? 为了处理这种情况,我们可以使用 Promise.allSettled() 。让我们也来了解一下。

Promise.allSettled()

它是 Promise.all() 的一个细微变体,区别在于 Promise.allSettled() 总是解决,无论传递给它的承诺是解决还是拒绝,它都会返回包含传递给它的承诺的结果的数组。

示例:

const promise1 = Promise.reject("failure");
const promise2 = 42;
const promise3 = new Promise((resolve) => {
    setTimeout(resolve, 100, 'foo');
});
Promise.allSettled([promise1, promise2, promise3]).then((results) => {
    console.log(results);
});
// 预期输出: 数组 [
//   { status: "rejected", reason: "failure" },
//   { status: "fulfilled", value: 42 },
//   { status: "fulfilled", value: 'foo' }
// ]

另一个有用的静态方法是 Promise.race() ,它可以用于为异步函数实现超时。让我们看看如何:

Promise.race()

Promise.race() 方法返回一个承诺,只要传递给它的数组中的任何一个承诺满足或拒绝,就以该承诺的满足值或拒绝原因来满足或拒绝。

示例

const promise1 = new Promise((resolve,reject)=>{
     setTimeout(resolve,500,'one');
})
const promise2 = new Promise((resolve,reject)=>{
     setTimeout(resolve,100,'two');
})
Promise.race([promise1,promise2]).then((value)=>{
     console.log(value);
     // 两者都解决,但 promise2 更快。
})
// 预期输出: 'two'

让我们看看如何使用它来实现超时:

function fetchData() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("Fast data");
    }, 6000);
  });
}
​
const fetchDataPromise = fetchData();
function fetchDataWithTimeout(promise,duration){
    return Promise.race(
         [
            promise,
            new Promise((_,reject)=>{
               setTimeout(reject,duration,"Too late.")
            })
         ]
    )
}
​
fetchDataWithTimeout(fetchDataPromise,5000).then((result)=>{
  console.log(result)
}).catch((error)=>{
  console.log(error)
})
/*
预期结果:
Too late
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

幻想多巴胺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值