首页 > 其他分享 >JS异步任务的并行、串行,以及二者结合

JS异步任务的并行、串行,以及二者结合

时间:2023-10-26 22:24:15浏览次数:31  
标签:异步 arr await 并行 JS item Promise 串行

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

 

一、并行

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

我们最经常用的,是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结束

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

 

本人水平非常有限,写作主要是为了把自己学过的东西捋清楚。如有错误,还请指正,感激不尽。

标签:异步,arr,await,并行,JS,item,Promise,串行
From: https://www.cnblogs.com/luzeyu/p/17790599.html

相关文章

  • Fabric.js 图案笔刷
    本文简介带尬猴,我是德育处主任Fabric.js有图案画笔功能,这个功能可以简单理解成“刮刮卡”效果。如果只是看Fabric.js文档可能还不太明白图案画笔PatternBrush是如何使用。本文将讲解如何配置这款画笔的基础属性。图案画笔(笔刷)PatternBrush先看看效果使用图案画......
  • js HmacSHA256 改python
      uu.HmacSHA256(JSON.stringify(e),t).toString(uu.enc.Base64)    defdemo2(t,account,password,rsaKey):importhmacimporthashlibimportbase64aaa=f'{{"account":"{account}","password":&qu......
  • 什么是yaml格式与json格式
    什么是yaml格式与json格式yaml格式:文件名格式以.yml.yaml为后缀,用空格缩进表示字段的层级关系,可读性高,易于人类管理yaml格式布尔值类型:只有在是true/false时为真,假的意识例:debug:true 布尔值类型debug:"true"字符串类型​debug:false  布尔值类型debu......
  • JS中的4个for循环
    JS中的4个for循环介绍在ECMAScript5(简称ES5)中,有三个循环。在2015年6月发布的ECMAScript6(简称ES6)中,新增了一种循环类型。他们是:forforinforeachforof一起来看看这4个for循环。1、简单的for循环最常见的写法:constarr=[1,2,3];for(leti=0;i<arr.l......
  • Three.js 材质的 blending
    Three.js材质的blending//blendingmodesexporttypeBlending=|typeofNoBlending|typeofNormalBlending|typeofAdditiveBlending|typeofSubtractiveBlending|typeofMultiplyBlending|typeofCustomBlending;//customblendin......
  • js--深拷贝和浅拷贝
    一、栈(stack)和堆(heap)栈(stack):由操作系统自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈;每种数据类型占用的空间大小是固定的。堆(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表;二、基本数据类型......
  • JS Date相关内容
    记录一些与Date有关的使用技巧、兼容问题等。1.newDate()接收参数兼容性:以下是所有浏览器都可支持的接收参数形式vard=newDate(2011,01,07);//yyyy,mm-1,ddvard=newDate(2011,01,07,11,05,00);//yyyy,mm-1,dd,hh,mm,ssvard=newDate("02......
  • Python_Json的使用总结
    应用场景json应用于批量数据进行组织管理--将无序变为有序-将输入结构数据进行组织形式标注化直观问题1.函数功能:dump在英文中有转储,转存的意思 json.dump(data,f) json.dump(data,f,indent=4)#使用缩进和换行格式化JSON dumps()dumps是dump......
  • 【2023最新10.25】全国建筑市场监管公共服务平台(四库一平台)js逆向
    目录js逆向思路第一步抓包第一种破解方法,堆栈法python还原js扣代码还原第二种破解方法,搜索法完整代码效果展示js逆向思路第一步看请求网址的发起程序都有哪些接在js文件搜索AES,MD5,等高频加密方式的字段1parse2decrypt3.toString()4Base645表单字段6url关键字......
  • jsp
    1.jsp表达式<%=  %> 等价于  ${}  就相当于输出  2.jsp的脚本片段  <%  %> 3.jsp声明 <%!  %>  4.jsp指令这两个都是一样: header和footer的内容放在网页主体的上下部分 9大内置对象主要用的4个  存东西取...转发......