说明
以下内容全部来自对async.js的源码分析,在日常工作中遇到最多的几个方法就是waterfull,parallel,series。所以,本文主要对该三个方法进行详细的分析,后续如有真实的使用场景也能做到得心应手。废话不多说,直接上代码:
1.如何保证函数只会被执行一次
![ca807af9116e69ec093ef9e7cb7ba652.png](https://i-blog.csdnimg.cn/blog_migrate/133658b8258d20ba429281a18e3a81d0.jpeg)
而下面的onlyOnce在被第二次调用的时候直接抛出错误:
![7f98cf6af06b019f31d35c4b1e673466.png](https://i-blog.csdnimg.cn/blog_migrate/1eac76edb0a58ed0abe2acb814834a03.jpeg)
2.如何创建一个迭代器对象
![8ab17f23bba28179fb47c49968acfc6b.png](https://i-blog.csdnimg.cn/blog_migrate/a92357ecdc8f3f784f33d3fd43b4415a.jpeg)
3.如何控制并发的数量
![61f497b81f830a42f9cc04e74e0cd89a.png](https://i-blog.csdnimg.cn/blog_migrate/7b7ca2e861a112076f51dcffd675de46.jpeg)
上面之所以重点讲解了:只会执行一次的函数,迭代器对象,控制并发数量的方式,是因为后面章节中会被反复使用。所以读到此处,建议对上面的内容好好咀嚼下!
4.waterfull vs parallel vs series异步方法详解
4.1 如何将同步函数包装为异步
顾名思义,asyncify就是将我们的常规的函数包装为异步的,接受参数加回调的方式,与nodejs中所有内部函数的签名保持一致。有了上面的工具函数源码解析,下面看看asyncify方法内部的具体逻辑:
![bc7f65c381f47df0c7c63f9f017c8d1b.png](https://i-blog.csdnimg.cn/blog_migrate/3dab30b2eb2976154f536a2ea86e5f92.jpeg)
有了对内部处理逻辑的分析,下面看看具体代码如何调用:
![ea2687607a4841c71b78e02a362be7e0.png](https://i-blog.csdnimg.cn/blog_migrate/9f51b55a3ab2c11e6f322a9981423ffc.jpeg)
这个asyncify函数接受一个同步函数,将它转化为异步的,同时将asyncify包裹的函数的返回值传递给回调函数callback。这个方法常用于:waterfall/series或者其他异步的函数。为asyncify返回的函数传递的任何参数会被传递给包裹的函数,但是不包括最后一个回调函数(initialParams中的args.pop调用后args已经改变了)。如果有错误抛出,那么也会被传入到callback回调。
如果传入asyncify函数的返回值是Promise,那么这个Promise的resolve ,reject状态会被传入到回调callback回调中。这也就是说你可以为asyncify传入async函数!
4.2 asyncify用于waterfull
下面是waterfall给出的完整的代码:
![b3e2a376179cacd23c7498604d944dfb.png](https://i-blog.csdnimg.cn/blog_migrate/1dda5b0bb99bc45d2090c8e772bf15f4.jpeg)
其中为每一个tasks中的函数都进行了asyncify处理,使得这个函数的签名为(...args,callback)。同时,因为asyncify处理的时候,会将包裹的函数的真实调用结果传递给callback回调,同时第一个参数为error。
下面是waterfall具体的调用代码实例:
![09079ecd490f279729acd943eeba982f.png](https://i-blog.csdnimg.cn/blog_migrate/31b12e41f1169ebfe347cd9a5bd9d7d1.jpeg)
也可以使用下面的方式来调用:
![ce567377bd414a6e1ca91d87b2f5f767.png](https://i-blog.csdnimg.cn/blog_migrate/278cdbb54ec013d238346aec189da51d.jpeg)
waterfull方法,顾名思义:就是在Collection中的前一个asyncify的函数执行完毕后,再将结果传递给下一个asyncify的函数,当所有的函数都执行完毕后,调用我们的callback回调。
4.3 asyncify用于parallel方法
上面的"如何控制并发的数量"部分已经说过如何控制并发遍历(eachOfLimt.js)。下面再讲一个用于不对并发量进行限制的方法(eachOf.js)。该方法可以用于对象和数组:
![00907f15376564be9480f0e8d11eb92a.png](https://i-blog.csdnimg.cn/blog_migrate/a19d1285786c4fe5ac15c24e2cd60562.jpeg)
上面的eachOf方法可以看出,每一个回调中并没有在callback中传入value,只是循环调用集合中的方法而已。下面是parallel的代码:
![a96fd6e8d3f2e7ba3f63732894939314.png](https://i-blog.csdnimg.cn/blog_migrate/a779edc081a0f95048be2ef2ac66261c.jpeg)
该方法的真实用法如下:
![ba12620bd0d6d5b061f501b4eeef874a.png](https://i-blog.csdnimg.cn/blog_migrate/615c58e085c5cdc4c271b98eeca3b4b2.jpeg)
注意:我们parallel回调函数的值也是按顺序的,即第一个回调函数的值,第二个回调函数的值....。parallel和waterfull的区别在于:parallel不会控制并发量,而waterfall必须等前一个函数执行结束后才会执行下一个方法,同时也会将前一个方法的值传递给后一个方法。而parallel因为是并发执行的,所以只能获取到最终的结果而不能获取到前一个函数的执行结果。
4.3 asyncify用于series
![7f8abbc75f8dfd602a0ce9f3d161c4f2.png](https://i-blog.csdnimg.cn/blog_migrate/85413f1c88d507ea8da39cf598a851b4.jpeg)
看看eachOfSeries.js方法的代码:
![f4231b6cb5cf7a72e31fbf4524941064.png](https://i-blog.csdnimg.cn/blog_migrate/73a3f4d3f91ac2d737d158cd3ab7140b.jpeg)
也就是series通过eachOfLimit.js将并发量控制为1。同时从series.js可以看到,它也使用了上面的parallel.js,所以它的返回值只可能是和parallel一样的类型,即results[key] = result类型。也就是说,虽然series方法可以保证代码按顺序执行,即前一个函数执行完毕才执行后面的函数(和parallel的主要区别),但是只有在回调函数中可以获取到所有函数的结果,而不能获取前一个函数的调用结果。下面是具体的例子:
![55b7aaa962f2667827499ed1242c8b27.png](https://i-blog.csdnimg.cn/blog_migrate/94239af6382d7a0b4017d3b1ac5af475.jpeg)
或者可以采用下面的方式:
![37303015f15ee3457d152ba5753d2bb4.png](https://i-blog.csdnimg.cn/blog_migrate/97ebd8791e1e74df3b3c4610d4655859.jpeg)
5.waterfull vs parallel vs series方法总结
从上面的分析知道,控制并发量其实就是控制了同一个时间最多执行的函数个数,其主要是通过eachOfLimit.js实现的。到这里,我想大家对于三个方法的区别和能力已经有了比较深入的了解了吧。我们下期再见吧
![554446aeaa8ad0ec3c01c9633433bde8.png](https://i-blog.csdnimg.cn/blog_migrate/2883a162106c5bbbf583a24aade18871.jpeg)