

手把手教你Promise小技巧——小程序接口数限制下的并行再顺序执行
source link: http://zackzheng.info/2020/06/07/use-reduce-to-run-promise-sequentially/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Promise
是一种异步编程的解决方案,在很多语言都有它的实现,笔者一直喜欢使用它去解决各种问题,简洁高效。
ECMAscript 6
原生提供了 Promise
对象。本文通过小程序上传接口并发数限制下进行上传的场景,实现图片并行再串行上传,分享 Promise
顺序执行的一种实现。
二、实现讲解
在 微信官方文档·小程序-网络使用说明
中,对 wx.request
、 wx.uploadFile
、 wx.downloadFile
的最大并发限制是 10
个。因此当遇到一个页面需要上传超过10个文件时,无法使用 Promise
并发调用上传接口。
比如页面有两个产品元素,一个元素需要上传5张照片,一个元素需要上传8张照片。此时我们操作后得到两个数组,一个包含5个上传的 Promise
,一个包含8个上传的 Promise
。我们可以数组内并行发起,数组间则顺序执行。
这样得到的逻辑就是,先并行上传第一个元素的5张照片,上传完再并行上传第二个元素的8张照片。(当然也可以将所有的上传按10个分批再顺序执行)
接下里我们一步步,从浅到深,分享下处理的思路。
1. 顺序执行两个Promise
在两个异步操作的情况下,使用 then
将两个 Promise
串起来:
a.then( _ => b );
2. 顺序执行多个Promise
在异步操作个数不确定的情况下,可以使用 reduce
将它们串起来:
// promiseArray 是数组,数组内对象是 Promise 类型 promiseArray.reduce( (p, f) => p.then(_ => f) );
使用 reduce
便是实现顺序执行的基础,理解清楚这行代码发生了什么,处理其他问题便可迎刃而解。
此处其实是第1点的高阶函数写法,同样是执行完前一个 Promise
之后,执行后一个 Promise
,然后将结果作为 Result
进行下一次循环。因此需要注意到,最终结果只包含了最后一个 Promise
的执行结果,没有其他 promise
的执行结果。
3. 顺序执行并获取所有结果
显然,我们是需要得到所有顺序执行的结果的,因此需要进行一定的处理。
我们可以对 reduce
内每一步的结果进行处理,组合成一个数组,此时需要用到 Promise.all
。
// promiseArray 是数组,数组内对象是 Promise 类型 promiseArray.reduce( (p, f) => p.then( res => Promise .all([Promise.resolve(res), f]) .then( res => Promise.resolve( res[0].concat([res[1]]) ) ) ), Promise.resolve([])); // 注意此处需要提供初始值,否则会出现不符合预期的结果
这是最终的处理,下面一步步讲解下。
上面第一个 res
是数组类型,存放了前面每个 Promise
执行成功后返回的结果。
Promise.all([Promise.resolve(res), f]);
此代码是用第一个 res
构造一个 Promise
,和 f
一起并行执行,最终会得到第二个 res
,它是一个数组,数组第一个对象是第一个 res
,第二个对象是 f
成功返回的数据。
Promise.resolve( res[0].concat([res[1]]);
此处将第二个 res
的第一个对象(数组类型)和第二个对象合并成一个新数组,并构造成一个 Promise
。
因此,最终会得到一个数组,该数组包含所有需要顺序执行的 Promise
的结果。
举例如下:
let promise1 = Promise.resolve('1'); let promise2 = Promise.resolve('2'); let promise3 = Promise.resolve('3'); [promise1, promise2, promise3].reduce((p, f) => p.then(res => Promise .all([Promise.resolve(res), f]) .then( res => Promise.resolve(res[0].concat([res[1]])) ) ), Promise.resolve([])).then( res => { console.log(res); });
运行结果:
> Array ["1", "2", "3"]
4. 先并行再顺序执行得到所有结果
理解了第3点,那么我们只需要将每个顺序执行的 Promise
,替换成多个并行执行的 Promise
。
举例如下:
let promise1 = Promise.all([Promise.resolve('11'), Promise.resolve('12'), Promise.resolve('13')]); let promise2 = Promise.all([Promise.resolve('21'), Promise.resolve('22'), Promise.resolve('23')]); let promise3 = Promise.all([Promise.resolve('31'), Promise.resolve('32'), Promise.resolve('33')]); [promise1, promise2, promise3].reduce( (p, f) => p.then( res => Promise.all([Promise.resolve(res), f]).then( res => Promise.resolve(res[0].concat([res[1]])) ) ) , Promise.resolve([]) ) .then( res => { console.log(res); });
运行结果:
> Array [Array ["11", "12", "13"], Array ["21", "22", "23"], Array ["31", "32", "33"]]
如果想要全部放一组:
let promise1 = Promise.all([Promise.resolve('11'), Promise.resolve('12'), Promise.resolve('13')]); let promise2 = Promise.all([Promise.resolve('21'), Promise.resolve('22'), Promise.resolve('23')]); let promise3 = Promise.all([Promise.resolve('31'), Promise.resolve('32'), Promise.resolve('33')]); [promise1, promise2, promise3].reduce( (p, f) => p.then( res => Promise.all([Promise.resolve(res), f]).then( res => Promise.resolve(res[0].concat(res[1])) ) ) , Promise.resolve([]) ) .then( res => { console.log(res); })
运行结果:
> Array ["11", "12", "13", "21", "22", "23", "31", "32", "33"]
区别只在 concat
的地方。
三、总结
其实复杂的 Promise
难写,也不难写。结合 reduce
,需要先考虑最终想要什么类型的数据,再对其进行处理,在强类型的语言中如ts、Swift,需要写明初始值的类型,不然会导致出错,耗费较长时间。
-END-
欢迎到我的博客交流: https://zackzheng.info
Recommend
-
33
前言:大家好,我叫邵威儒,大家都喜欢喊我小邵,学的金融专业却凭借兴趣爱好入了程序猿的坑,从大学买的第一本vb.net和自学vb.net,我就与编程结下不解之缘,随后自学易语言写游戏辅助、交易软件,至今进入了前端领域,看到不少朋友都写文章分享,自己也弄一个玩...
-
56
我们在分析数据时只需记住一点,这钱花得值吗?不值就有问题,就需要去找出原因。 作者:Deity 来源:心魔营销 本...
-
61
概念 Generator 函数是 ES6 提供的一种异步编程解决方案,执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的
-
7
1套公式,20个技巧,手把手教你打造高转化社群 运营插班生 2021-11-14 0 评论...
-
8
手把手教你搭建答题活动小程序系列文章,第一阶段为界面设计篇,分别描写了如何搭建答题小程序界面。现在已经进入第二阶段,功能交互篇。而上一篇文章描写了,如何用云开发实现查询题库功能...
-
9
文章中提到的命令行工具即是Windows Terminal/PowerShell/cmd其中的一个,推荐使用Windows Terminal 运行命令行工具的时候建议以管理员身份,避免踩坑 为了保证操作...
-
5
本文首发:Postman 使用教程 - API 接口自...
-
24
深入理解 Promise 之手把手教你写一版 出处:mp.weixin.qq.com ...
-
9
一、创建ASP.NET Core Web API项目(若项目已创建,则可跳过本节内容) 1、双击打开VS2022。 2、单击“创建新项目”,如下图。
-
4
传送门:从0到1手把手教你ASP.NET Core Web API项目配置接口文档Swagger(一) 一、设置Swagger页面为首页——开发环境 我们虽然可以在输入 /sw...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK