2021-4-26-async.js中文文档

Async Logo

For Async v1.5.x documentation, go HERE

Async 是一个功能强大的异步 JavaScript 模块。虽然最初是为了与 Node.js 一起使用,可以通过 npm i async安装,
它也可以直接在浏览器中使用。

Async 也能通过 yarn 安装:

  • yarn: yarn add async

Async提供了大约70个函数。其中包括集合 (map, reduce, filter, each…) 的异步扩展。以及常见的异步控制流模式 (parallel, series, waterfall…). 这些函数假定您遵循Node.js约定 (提供一个callback作为异步函数的最后一个参数-- 一个期望错误作为其第一个参数的回调—并调用回调一次)。

你也可以用 async 函数代替 callback-accepting 函数提供给 Async 方法. 更多信息,请参考 AsyncFunction

Quick Examples

async.map(['file1','file2','file3'], fs.stat, function(err, results) {
    // results is now an array of stats for each file
});

async.filter(['file1','file2','file3'], function(filePath, callback) {
  fs.access(filePath, function(err) {
    callback(null, !err)
  });
}, function(err, results) {
    // results now equals an array of the existing files
});

async.parallel([
    function(callback) { ... },
    function(callback) { ... }
], function(err, results) {
    // optional callback
});

async.series([
    function(callback) { ... },
    function(callback) { ... }
]);

还有更多的功能哦,请查看后面完整功能列表。如果您觉得还缺了点什么,请创建一个GitHub issue 给我们。

常见问题 (StackOverflow)

同步迭代函数 (Synchronous iteration functions)

在使用async的时候,如果你遇到类似 RangeError: Maximum call stack size exceeded.的报错或者其他栈溢出问题 , 你可能使用了同步迭代。使用“同步”,意味着一个方法与它的callback在同一个事件循环(javascript event loop)中执行,使用 I/O 或者 定时器 除外。调用太多的callback会使栈溢出。如果你遇到这个问题,只需要通过async.setImmediate方法启动一个新的调用栈在下一次事件循环中运行。

如果在某些情况下提早回调,这也偶然会产生:

async.eachSeries(hugeArray, function iteratee(item, callback) {
    if (inCache(item)) {
        callback(null, cache[item]); // 如果太多的项目被缓存,也会栈溢出
    } else {
        doSomeIO(item, callback);
    }
}, function done() {
    //...
});

该成这样:

async.eachSeries(hugeArray, function iteratee(item, callback) {
    if (inCache(item)) {
        async.setImmediate(function() {
            callback(null, cache[item]);
        });
    } else {
        doSomeIO(item, callback);
        //...
    }
});

出于性能考虑,Async没有做同步迭代器校验。如果仍然遇到堆栈溢出,可以按照上面的方法进行延迟。或者使用async.ensureAsync方法包装函数,这些函数本质上是异步的,因此不存在此问题,也不需要额外的回调延迟。

如果JavaScript的事件循环仍然有点模糊,请查看this article or this talk 获取更多详细信息。

多次调用回调函数( Multiple callbacks)

确保在调用callback后return这个函数,否则在许多情况下会导致多次回调和不可预知的行为。

async.waterfall([
    function(callback) {
        getSomething(options, function (err, result) {
            if (err) {
                callback(new Error("failed getting something:" + err.message));
                // we should return here
            }
            // since we did not return, this callback still will be called and
            // `processData` will be called twice
            callback(null, result);
        });
    },
    processData
], done)

每当回调调用不是函数的最后一个语句时,最好使用 return callback(err, result)

Using ES2017 async functions

Async 可以用 async functions 代替 Node-风格 回调函数。没有callback形参,通过return 替代callback(null,result)。通过抛异常throw new Error()代替 callback(err)

async.mapLimit(files, 10, async file => { // <- no callback!
    const text = await util.promisify(fs.readFile)(dir + file, 'utf8')
    const body = JSON.parse(text) // <- a parse error here will be caught automatically
    if (!(await checkValidity(body))) {
        throw new Error(`${file} has invalid contents`) // <- this error will also be caught
    }
    return body // <- return a value!
}, (err, contents) => {
    if (err) throw err
    console.log(contents)
})

我们只能识别到原生async functions,不包括被转移的版本(e.g. with Babel)。另外您可以通过async.asyncify()async functions 包装成 node-style callback

绑定上下文 Binding a context to an iteratee

传递给Async的异步函数,this的上下文指向会被改变,需要通过bind方法指定上下文

// Here is a simple object with an (unnecessarily roundabout) squaring method
var AsyncSquaringLibrary = {
    squareExponent: 2,
    square: function(number, callback){
        var result = Math.pow(number, this.squareExponent);
        setTimeout(function(){
            callback(null, result);
        }, 200);
    }
};

async.map([1, 2, 3], AsyncSquaringLibrary.square, function(err, result) {
    // result is [NaN, NaN, NaN]
    // This fails because the `this.squareExponent` expression in the square
    // function is not evaluated in the context of AsyncSquaringLibrary, and is
    // therefore undefined.
});

async.map([1, 2, 3], AsyncSquaringLibrary.square.bind(AsyncSquaringLibrary), function(err, result) {
    // result is [1, 4, 9]
    // With the help of bind we can attach a context to the iteratee before
    // passing it to Async. Now the square function will be executed in its
    // 'home' AsyncSquaringLibrary context and the value of `this.squareExponent`
    // will be as expected.
});

内存泄漏 Subtle Memory Leaks

在某些情况下,当您在另一个异步函数中调用Async方法时,您可能想尽早退出异步流:

function myFunction (args, outerCallback) {
    async.waterfall([
        //...
        function (arg, next) {
            if (someImportantCondition()) {
                return outerCallback(null)
            }
        },
        function (arg, next) {/*...*/}
    ], function done (err) {
        //...
    })
}

有时候你想跳过瀑布流的剩余过程,你调用了外部的回调函数,但是Async还是会等待内部的next函数被调用,从而造成函数没有正确结束。

从 3.0版本, 你可以调用任何 false 作为 error 参数的Async 回调,让Async结束方法。

        function (arg, next) {
            if (someImportantCondition()) {
                outerCallback(null)
                return next(false) // ← signal that you called an outer callback
            }
        },

处理集合时对集合进行改变 Mutating collections while processing them

如果你通过一个数组去调用Async的集合方法(例如 each, mapLimit, or filterSeries),
然后数组被push, pop, or splice 这些方法修改,这可能会导致意外,或者不确定的行为。Async会迭代到满足数组的原始 length次数。一些 push, pop, or splice 的索引已经被处理。因此,不建议在异步开始对其进行迭代之后修改该数组。 如果确实需要push, pop, or splice,请改用 queue

下载


GitHub下载源码.
也可以通过npm安装:

$ npm i async

然后 require()引入整个模块:

var async = require("async");

或缺部分引入某个方法:

var waterfall = require("async/waterfall");
var map = require("async/map");

开发版: async.js - 29.6kb 未压缩

在浏览器 In the Browser

Async 可以运行在任何 ES2015 环境 (Node 6+ and all modern browsers).

如果你想在更老的环境中使用Async, (e.g. Node 4, IE11) 你需要做如下转换.

Usage:

<script type="text/javascript" src="async.js"></script>
<script type="text/javascript">

    async.map(data, asyncProcess, function(err, results) {
        alert(results);
    });

</script>

Async 的可移植版本, 包含 async.js and async.min.js, 在 /dist 文件夹下. Async 支持 jsDelivr CDN.

ES Modules 支持

Async包含一个 .mjs版本,该版本应由兼容的打包工具自动使用,例如Webpack或Rollup等任何使用 package.jsonmodule字段的东西。

我们还在npm上的另一个async-es包中提供Async作为纯ES2015模块的集合。

$ npm install async-es
import waterfall from 'async-es/waterfall';
import async from 'async-es';

Typescript 支持

Async 的第三方类型定义。

npm i -D @types/async

建议在您的tsconfig.json中编译选项中配置ES2017或更高版本,这样会保留async函数:

{
  "compilerOptions": {
    "target": "es2017"
  }
}

其他仓库(友情链接)

  • limiter a package for rate-limiting based on requests per sec/hour.
  • neo-async an altername implementation of Async, focusing on speed.
  • co-async a library inspired by Async for use with co and generator functions.
  • promise-async a version of Async where all the methods are Promisified.

docjs 文档

不是很好翻译,直接看官方英文的
https://caolan.github.io/async/



---------华丽的分割线, 后面是我的理解------------------



Async 主要包含三个部分的函数

1. 对集合的异步拓展,Array.prototype上方法的补充,原生是不支持异步的

  • concat
  • detect find
  • each forEach --不带index
  • eachOf forEachOf --带index
  • every
  • filter
  • groupBy
  • map
  • mapValues
  • reduce reduceRight transform --都是做累加的
  • reject --filter的补集
  • some
  • sortBy
  • 以上方法又有Limit变体版本
  • Limit是限制并发数量的
  • Series又是Limit并发数为1的变体版本

2. 异步工作流

  • 工作流

    • queue 队列,执行器只能拿到当前执行的任务
    • priorityQueue 跟queue相同,但是任务带执行优先级
    • cargo 队列,执行器中拿到队列中的所有任务信息
    • waterfall 瀑布,从上往下执行,最后的回调拿到瀑布中最后一个函数的执行结果
    • series 一个一个运行,最后的回调拿到所有函数的执行结果
    • auto 自动运行,根据异步函数的依赖关系自动执行
    • times 执行同一个函数多次
    • retry 执行失败会重试,直到成功(默认重试5次,重试间隔0秒)
    • forever 一直执行这个函数,除非报错
  • Promise对应的Async实现

    • parallel 一起执行,任何一个报错就退出,等同于Promise.all [拿到全部正确的结果]
    • Promise.allSettled [拿到全部结果,不论对错],这个Async没有对应的实现,reflect和reflectAll可以阻止错误终端工作流
    async.allSettled=async.parallel(async.reflectAll(tasks))
    
    • tryEach 任何一个异步函数成功就会退出工作流,等同于Promise.any [拿到第一个正确的结果]
    • race 任何一个异步函数成功或者失败就是退出工作流,等同于Promise.race[拿到第一个执行完成的结果,不论对错]
  • 循环工作流

    • whilst while(condition){statement} 条件满足继续循环
    • doWhilst do{statement}while(condition) 至少会执行一次
    • until loop{}until(condition) 条件满足退出循环
    • doUntil do{}until(condition) 至少会执行一次
  • 辅助函数
    • compose 打散管道方法 例如 a(b(c())) compose(a,b,c)
    • seq compose的可读版本 seq(a,b,c) 对应的是 c(b(a()))
    • applyEach 多个异步方法的参数相同,并发版
    • applyEachSeries 多个异步方法的参数相同,排队版

3. 辅助函数

  • apply 多参数转换成只有一个callback参数的函数
  • asyncify,wrapSync 包装 ES2017 async function 成 Node-style风格AsyncFunction
  • constant 包装常量成 AsyncFunction
  • dir,log 方便调试输出异步函数的执行结果
  • ensureAsync 确保函数是异步执行,防止同步调用迭代栈溢出
  • memoize unmemoize 慢函数增加缓存,清除缓存
  • nextTick 将函数放入下一次事假循环执行
  • reflect reflectAll 返回一个新的函数,及时callback(error)也不会导致工作流结束
  • setImmediate 跟nextTick差不多
  • timeout 给异步函数增加超时
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容

  • 凌波微步有云: 此步法精妙异常,习者可以用来躲避众多敌人的进攻,此外「凌波微步」每踏出一步,都与内力息息相关,决非...
    张晓衡阅读 2,280评论 8 12
  • #Node课程大纲V10(一周) ##目录 *1day -基本介绍 -环境配置(nodenvm,cnpm) -RE...
    lint_b7d1阅读 180评论 0 0
  • 1.Promise 1.简介 Promise,简单来说就是一个容器,里面保存着某个未来才会结束的时间(通常是一个异...
    Grandperhaps阅读 937评论 0 1
  • ES7的async/await语法在2016年就已经提出来了,惭愧的是我最近才接触使用,,下面来聊聊 解决了什么问...
    Zal哥哥阅读 227评论 0 0
  • 本文来自 悟尘纪,获取更新内容可查看原文: https://www.lixl.cn/2020/011231581....
    悟尘80阅读 364评论 0 1