JS异步任务的并行、串行及二者结合用法

 更新时间:2023年10月27日 09:13:56   作者:路泽宇  
让多个异步任务按照我们的想法执行,是开发中常见的需求,今天我们就来捋一下,如何让多个异步任务并行,串行,以及并行串行相结合,感兴趣的朋友跟随小编一起看看吧

让多个异步任务按照我们的想法执行,是开发中常见的需求。今天我们就来捋一下,如何让多个异步任务并行,串行,以及并行串行相结合。

一、并行

并行是使用最多的方式,多个相互间没有依赖关系的异步任务,并行执行能够提高效率。

我们最经常用的,是Promise.all() 。

function f1() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('1结束');
            resolve();
        }, 1000)
    });
}
function f2() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('2结束');
            resolve();
        }, 900)
    });
}
function f3() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('3结束');
            resolve();
        }, 800)
    });
}

let arr = [f1, f2, f3];
Promise.all(arr.map(i => i()));
// 3结束
// 2结束
// 1结束

以下几种数组遍历方式,同样可以实现并行。

// forEach遍历
arr.forEach(item => {
    item();
});
// for循环
for (let i = 0; i < arr.length; i++) {
    arr[i]();
}
// for...of遍历
for (let item of arr) {
    item();
}

// 注意,以下两种写法同样是并行的
arr.forEach(async item => await item());

async function f() {
    arr.forEach(async item => await item())
}
f();

相比之下,Promise.all()可以确保任务都执行成功,然后再执行后续操作,这是各种遍历无法做到的。

另外,还有一种方式也能实现并行:Promise.allSettled()。

Promise.allSettled(arr.map(i => i()));

这种方式很特别,它无法得到每个Promise对象的返回值,却可以精确得知每个任务的成功还是失败。如果你有这样的需求场景,用Promise.allSettled()就很合适。

二、串行

我在工作中遇到过一个场景,一个有1000+元素的数组,每个成员都是调用第三方接口的Promise对象。我像往常一样得意的使用Promise.all(),等着1000多个任务瞬间完成。然而,结果却让我大跌眼镜,这1000多个任务,只有一部分成功了,大部分都报错了。不管我执行几次,结果都是这个样。一筹莫展之后,我才从第三方那儿得知,他们的接口是有调用限制的,一个接口同一时间只能并行300个。

有没有办法能让它们一个接一个的执行呢?也就是串行。

nodejs koa框架的next()语法给了我启发,它就是让中间件一个接一个的执行。于是我想出了递归的方式:

async function serial(arr) {
    let item = arr.shift();

    await item();
    if (arr.length > 0) {
        await serial(arr);
    }
}
serial(arr);
// 1结束
// 2结束
// 3结束

其实,想让异步任务串行,不用这么麻烦。以下遍历的方式,同样可以实现串行。

// 使用for...of
async function f() {
    for (let item of arr) {
        await item();
    }
}
f();

// 使用for循环
async function f() {
    for (let i = 0; i < arr.length; i++) {
        await arr[i]();
    }
}
f();

发现了没?为什么同样是for循环,同样是for...of,前面的写法是并行,后面就成了串行呢?

工作中,我们一定做过这样的尝试,想通过遍历,来让多个异步任务串行。但往往不得其法,怎么折腾它们都还是同时执行。

后一种写法,你可以理解为:await执行完成后,才会进入下一次循环。 其实,遍历,就相当于把每一个元素,在代码中从上到下写下来。当它们处于async函数中,并在每个元素前面加await,它们自然就能顺序执行。否则,我们都知道,简单的顺序写下来的异步任务,它们还是同时执行的。

好了,现在程序不报错了。但是,1000多个任务依次执行完成,足足花了十多分钟,太慢了!有没有办法,又快又不触发接口调用限制呢?

有,如果可以并行200个任务,完成后再开始下一轮200个......也就是,把并行和串行相结合。

三、并行串行结合

async function bingChuan(arr, num) {
    let items = arr.splice(0, num);
    
    await Promise.all(items.map(i => i()));
    if (arr.length > 0) {
        await bingChuan(arr, num);
    }
}
bingChuan(arr, 2);
// 2结束
// 1结束
// 3结束

好了,现在可以同时享有并行和串行的好处了!

到此这篇关于JS异步任务的并行、串行,以及二者结合的文章就介绍到这了,更多相关js异步任务并行内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • js判断undefined类型,undefined,null, 的区别详细解析

    js判断undefined类型,undefined,null, 的区别详细解析

    本篇文章主要是对js判断undefined类型,undefined,null,NaN的区别进行了详细的分析介绍,需要的朋友可以过来参考下,希望对大家有所帮助
    2013-12-12
  • 微信小程序中获取设备信息的方法

    微信小程序中获取设备信息的方法

    这篇文章主要给大家介绍了关于微信小程序中获取设备信息的相关资料,微信小程序是一种在微信平台上运行的应用程序,它具有轻量化、便捷性和高兼容性的特点,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-07-07
  • 14 个折磨人的 JavaScript 面试题

    14 个折磨人的 JavaScript 面试题

    这篇文章主要为大家详细介绍了14 个折磨人的 JavaScript 面试题,希望对大家有所帮助,感兴趣的小伙伴们可以参考一下
    2016-08-08
  • swiper自定义分页器的样式

    swiper自定义分页器的样式

    这篇文章主要为大家详细介绍了swiper自定义分页器的样式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-09-09
  • javascript定时器的简单应用示例【控制方块移动】

    javascript定时器的简单应用示例【控制方块移动】

    这篇文章主要介绍了javascript定时器的简单应用,结合javascript事件触发控制方块移动操作分析了javascript定时器使用相关操作技巧,需要的朋友可以参考下
    2019-06-06
  • 教你一步步实现一个简易promise

    教你一步步实现一个简易promise

    Promise是异步编程的一种解决方案,比传统的解决方案回调函数和事件更合理且更强大,这篇文章主要给大家介绍了关于如何一步步实现一个简易promise的相关资料,需要的朋友可以参考下
    2021-11-11
  • webpack进阶——缓存与独立打包的用法

    webpack进阶——缓存与独立打包的用法

    本篇文章主要介绍了webpack进阶——缓存与独立打包的用法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • js中arguments对象的深入理解

    js中arguments对象的深入理解

    这篇文章主要给大家介绍了关于js中arguments对象的深入理解,文中通过示例代码介绍的非常详细,对大家学习或者使用javascript具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-05-05
  • Asp.Net之JS生成分页条的方法

    Asp.Net之JS生成分页条的方法

    下面小编就为大家带来一篇Asp.Net之JS生成分页条的方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-11-11
  • js如何获取访问IP、地区、当前操作浏览器

    js如何获取访问IP、地区、当前操作浏览器

    这篇文章主要介绍了js如何获取访问IP、地区、当前操作浏览器,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-07-07

最新评论