串行流程、並行流程、混合執行
series, waterfall; parallel, parallelLimit; auto;
有多個異步函數須要依次調用,一個完成以後才能執行下一個。各函數之間沒有數據的交換,僅僅須要保證其執行順序。這時可以使用series。node
async.series([ function(callback) { // do some stuff ... callback(null, 'one'); }, function(callback) { // do some more stuff ... callback(null, 'two'); } ], // optional callback function(err, results) { // results is now equal to ['one', 'two'] });
另外還須要注意的是:多個series調用之間是不分前後的,由於series自己也是異步調用。ios
與seires類似,按順序依次執行多個函數。不一樣之處,每個函數產生的值,都將傳給下一個函數。若是中途出錯,後面的函數將不會被執行。錯誤信息以及以前產生的結果,將傳給waterfall最終的callback。web
注意,該函數不支持json格式的tasks。json
async.waterfall([ function(callback) { callback(null, 'one', 'two'); }, function(arg1, arg2, callback) { // arg1 now equals 'one' and arg2 now equals 'two' callback(null, 'three'); }, function(arg1, callback) { // arg1 now equals 'three' callback(null, 'done'); } ], function (err, result) { // result now equals 'done' });
並行執行多個函數,每一個函數都是當即執行,不須要等待其它函數先執行。傳給最終callback的數組中的數據按照tasks中聲明的順序,而不是執行完成的順序。axios
若是某個函數出錯,則馬上將err和已經執行完的函數的結果值傳給parallel最終的callback。其它未執行完的函數的值不會傳到最終數據,但要佔個位置。api
同時支持json形式的tasks,其最終callback的結果也爲json形式。數組
示例代碼:瀏覽器
async.parallel([ function(callback) { setTimeout(function() { callback(null, 'one'); }, 200); }, function(callback) { setTimeout(function() { callback(null, 'two'); }, 100); } ], // optional callback function(err, results) { // the results array will equal ['one','two'] even though // the second function had a shorter timeout. });
以json形式傳入tasks緩存
async.parallel({ one: function(callback) { setTimeout(function() { callback(null, 1); }, 200); }, two: function(callback) { setTimeout(function() { callback(null, 2); }, 100); } }, function(err, results) { // results is now equals to: {one: 1, two: 2} });
parallelLimit 與上面的 parallel 最大的不一樣就是限制最大同時執行的數量session
async.parallelLimit([(cb) => { setTimeout(() => { cb(null, 'one'); }, 1000); }, (cb) => { setTimeout(() => { cb(null, 'two'); }, 2000); }], 1, (err, value) => { log(value); }); // 需時3s左右
用來處理有依賴關係的多個任務的執行。好比某些任務之間彼此獨立,能夠並行執行;但某些任務依賴於其它某些任務,只能等那些任務完成後才能執行。
如異步獲取兩個數據並打印:
async.auto({ getData: function (callback) { setTimeout(() => { log('data got') callback(null, 'data'); }, 3000); }, getAnotherData: function (callback) { setTimeout(() => { log('another data got') callback(null, 'another data'); }, 1000); }, printData: ['getData', 'getAnotherData', function (result, callback) { log(result); }] }); // another data got // data got // { getAnotherData: 'another data', getData: 'data' }
Dependent tasks are specified as parameters to the function
能夠說算是 auto 方法的語法糖
async.autoInject({ getData: function (callback) { axios({ methods: 'get', url: 'http://baidu.com/' }).then(d => callback(null, d.status)) }, getAnotherData: function (callback) { axios({ methods: 'get', url: 'http://sogou.com/' }).then(d => callback(null, d.status)) }, writeFile: function (getData, getAnotherData, callback) { fs.writeFile('./d.json', JSON.stringify([getData, getAnotherData]), function (err) { if (err) { callback(err) } else { callback(null, 'finish') } }) } }, function (err, result) { if (err) { console.log(err) } else { console.log(result) // { getData: 200, getAnotherData: 200, writeFile: 'finish' } } })
至關於while,但其中的異步調用將在完成後纔會進行下一次循環。舉例以下:
var count = 0; async.whilst( () => { return count < 5; }, // 是否知足條件 (callback) => { // 知足條件執行函數 count++; setTimeout(() => { log(count) callback(null, count); }, 1000); }, (err, value) => { // 不知足條件完成循環 log('result: ' + count); } );
首先執行函數
count = 0; async.doWhilst((callback) => { // 先執行函數 count++; setTimeout(() => { log(count); callback(null, count); }, 1000); }, () => { // 後驗證條件 return count < 5; }, (err, value) => { // 主回調 log('result: ' + count); });
var count = 0; async.until( () => { return count >= 5; }, (callback) => { count++; setTimeout(() => { log(count) callback(null, count); }, 1000); }, (err, value) => { log('result: ' + count); } );
var count = 0; async.doUntil( (callback) => { // 先執行 count++; setTimeout(() => { log(count) callback(null, count); }, 1000); }, () => { return count >= 5; }, // 後驗證 (err, value) => { log('result: ' + count); } );
與whilst相似,但測試的是一個異步函數的回調(err, true or false),判斷回調第二參數是否爲真
count = 0 async.during(callback => { callback(null, count < 5) }, callback => { count++ console.log(count) setTimeout(callback, 1000); }, err => { if (err) console.log(err) console.log('finish') })
count = 0 async.doDuring( function (callback) { // 先執行一次 count++; log(count); setTimeout(callback, 1000); }, function (callback) { // 判斷是否知足條件 return callback(null, count < 5); }, function (err) { // 5 seconds have passed log('finished'); } );
在返回錯誤以前,嘗試從函數得到成功響應的次數不超過規定的次數。 若是任務成功,則回調將傳遞成功任務的結果。 若是全部嘗試都失敗,回調將傳遞最終嘗試的錯誤和結果。
async.retry({times: 3, interval: 200}, apiMethod, function(err, result) { log(result); }); // 嘗試三次,間隔200,打印結果
包裝任務使其能夠retry
async.auto({ dep1: async.retryable(3, getFromFlakyService), process: ["dep1", async.retryable(3, function (results, cb) { maybeProcessData(results.dep1, cb); })] }, callback);
調用 n 次,序號 n 可做爲參數傳入函數
async.times(5, (n, next) => { axios({ methods: 'get', url: 'http://sogou.com/' }).then(d => next(null, d.status)).catch(e => next(e)) }, (err, result) => { if (err) { console.log(err) } else { console.log(result) // [ 200, 200, 200, 200, 200 ] } })
timesLimit(count, limit, iteratee, callback)
The same as times but runs only a single async operation at a time.
timesSeries(n, iteratee, callback)
記得調用 next
async.forever((next) => {
setTimeout(() => { axios({ methods: 'get', url: 'http://www.baidu.com/' }).then(d => console.log(d.status)).then(next) }, 1000)
}, error => {
if (error) { console.log(error) }
})
Async提供了不少針對集合的函數,能夠簡化咱們對集合進行異步操做時的步驟
對全部集合中的全部元素,都執行同一個函數,並行:
Note, that since this function applies iteratee to each item in parallel, there is no guarantee that the iteratee functions will complete in order.不可以保證按照順序完成
let data = [ 'http://www.baidu.com', 'http://www.sogou.com', 'http://www.bing.com', ]; async.each(data, (item, callback) => { console.log('processing...' + item); axios({ methods: 'get', url: item }).then(d => { console.log(d.data.length); callback(); }); }, (err) => { if (err) console.log(err); }); // processing...http://www.baidu.com // processing...http://www.sogou.com // processing...http://www.bing.com // 22430 // 111984 // 116593
The same as each but runs a maximum of limit async operations at a time.
let data = [ 'http://www.baidu.com', 'http://www.sogou.com', 'http://www.bing.com', ]; async.eachLimit(data, 2, (item, callback) => { console.log('processing...' + item); axios({ methods: 'get', url: item }).then(d => { console.log(d.data.length); callback(); }); }, (err) => { if (err) console.log(err); }); // processing...http://www.baidu.com // processing...http://www.sogou.com // 22430 // processing...http://www.bing.com // 112087 // 116593
Like each, except that it passes the key (or index) as the second argument to the iteratee. 執行的函數有三個參數分別是:item, index, callback
let data = [ 'http://www.baidu.com', 'http://www.sogou.com', 'http://www.bing.com', ]; // async.forEachOf(data, (item, index, callback) => { forEachOf 與 eachOf 相同 async.eachOf(data, (item, index, callback) => { console.log('processing...NO.' + index); axios({ methods: 'get', url: item }).then(d => { console.log(d.data.length); callback(); }); }, (err) => { if (err) console.log(err); }); // processing...NO.0 // processing...NO.1 // processing...NO.2 // 112477 // 22430 // 116593
The same as eachOf but runs a maximum of limit async operations at a time. 多個限制參數,再也不累述
The same as eachOf but runs only a single async operation at a time. 至關於eachOfLimit 限制爲 1
let data = [ 'http://www.baidu.com', 'http://www.sogou.com', 'http://www.bing.com', ]; async.eachOfSeries(data, (item, index, callback) => { console.log('processing...NO.' + index); axios({ methods: 'get', url: item }).then(d => { console.log(d.data.length); callback(); }); }, (err) => { if (err) console.log(err); }); // processing...NO.0 // 111979 // processing...NO.1 // 22430 // processing...NO.2 // 116593
至關於 eachLimit 限制爲 1
there is no guarantee that the iteratee functions will complete in order 不保證按順序完成
let data = [ 'http://www.baidu.com', 'http://www.sogou.com', 'http://www.bing.com', ]; async.map(data, (item, callback) => { console.log('processing...NO.' + item); axios({ methods: 'get', url: item }).then(d => { callback(null, d.data.length); }); }, (err, value) => { if (err) console.log(err); console.log(value); }); // processing...NO.http://www.baidu.com // processing...NO.http://www.sogou.com // processing...NO.http://www.bing.com // [112677, 22430, 116593]
與 map 類似,多了限制參數
至關於 mapLimit 限制 1
用於處理對象
A relative of map, designed for use with objects. 針對遍歷對象值的狀況
let obj = { site1: 'http://www.baidu.com', site2: 'http://www.sogou.com', site3: 'http://www.bing.com' }; async.mapValues(obj, (value, key, callback) => { console.log('processing...NO.' + key); axios({ methods: 'get', url: value }).then(d => { callback(null, d.data.length); }); }, (err, value) => { if (err) console.log(err); console.log(value); }); // processing...NO.site1 // processing...NO.site2 // processing...NO.site3 // { site1: 112122, site2: 22430, site3: 116593 }
多了限制參數
至關於 mapValuesLimit 限制 1
返回的是經過測試的原始數據,只有篩選,沒有修改原始數據
Returns a new array of all the values in coll which pass an async truth test. 過濾返回通過驗證結果爲真的This operation is performed in parallel, but the results array will be in the same order as the original. 最終結果將與原始數據的順序一致
let data = [ 'http://www.baidu.com', 'http://www.sogou.com', 'http://www.bing.com', ]; async.filter(data, (item, callback) => { console.log('processing...NO.' + item); axios({ methods: 'get', url: item }).then(d => { let length = d.data.length; if (length > 100000) { callback(null, true); } else { callback(null, false); } }); }, (err, value) => { if (err) console.log(err); console.log(value); }); // processing...NO.http://www.baidu.com // processing...NO.http://www.sogou.com // processing...NO.http://www.bing.com // ['http://www.baidu.com', 'http://www.bing.com']
...
...
與filter相反,經過驗證的,予以剔除
The opposite of filter. Removes values that pass an async truth test.
...
...
Returns the first value in coll that passes an async truth test. 獲取集合中第一個知足測試的數據
let data = [ 'http://www.sogou.com', 'http://www.baidu.com', 'http://www.bing.com', ]; async.detect(data, (item, callback) => { console.log('processing...NO.' + item); axios({ methods: 'get', url: item }).then(d => { let length = d.data.length; if (length > 100000) { callback(null, true); } else { callback(null, false); } }); }, (err, value) => { if (err) console.log(err); console.log(value); }); // processing...NO.http://www.sogou.com // processing...NO.http://www.baidu.com // processing...NO.http://www.bing.com // http://www.baidu.com
...
...
If any iteratee call returns true, the main callback is immediately called. 一旦有符合條件的數據,立刻觸發主回調函數
let data = [ 'http://www.sogou.com', 'http://www.baidu.com', 'http://www.bing.com', ]; async.some(data, (item, callback) => { axios({ methods: 'get', url: item }).then(d => { let length = d.data.length; if (length > 100000) { callback(null, true); } else { callback(null, false); } }); }, (err, isSatisfied) => { if (err) console.log(err); console.log(isSatisfied); // true });
...
...
Returns true if every element in coll satisfies an async test. If any iteratee call returns false, the main callback is immediately called. 所有知足條件時返回true
let data = [ 'http://www.sogou.com', 'http://www.baidu.com', 'http://www.bing.com', ]; async.every(data, (item, callback) => { axios({ methods: 'get', url: item }).then(d => { let length = d.data.length; if (length > 0) { callback(null, true); } else { callback(null, false); } }); }, (err, isSatisfied) => { if (err) console.log(err); console.log(isSatisfied); // true });
...
...
將結果合併,一樣的,不能保證結果按照原來的順序排序
let data = [ 'http://www.sogou.com', 'http://www.baidu.com', 'http://www.bing.com', ]; async.concat(data, (item, callback) => { axios({ methods: 'get', url: item }).then(d => { callback(null, { item: item, length: d.data.length }); }); }, (err, value) => { if (err) console.log(err); console.log(value); }); // [ { item: 'http://www.sogou.com', length: 22430 }, // { item: 'http://www.baidu.com', length: 111979 }, // { item: 'http://www.bing.com', length: 116550 } ]
...
...
傳入一系列對象,並根據設置的 key 進行分組
let data = [{ year: 2001, url: 'http://www.baidu.com' }, { year: 2001, url: 'http://www.sogou.com' }, { year: 2017, url: 'http://www.bing.com' }] async.groupBy(data, (item, callback) => { axios({ methods: 'get', url: item.url }).then(d => { callback(null, item.year); // 按照 year 分組 }); }, (err, value) => { if (err) console.log(err); console.log(value); }); // { // '2001': // [{ year: 2001, url: 'http://www.baidu.com' }, // { year: 2001, url: 'http://www.sogou.com' }], // '2017': [{ year: 2017, url: 'http://www.bing.com' }] // }
...
...
Reduces coll into a single value 逐漸累加This function only operates in series. 只支持 series 模式,不支持並行
This function is for situations where each step in the reduction needs to be async; if you can get the data before reducing it, then it's probably a good idea to do so. 適合每一 reduce 步都須要異步獲取數據的狀況
async.reduce([2, 3, 4], 1, (memo, item, callback) => { // 1 爲 memo setTimeout(() => { callback(null, memo + item); }, 100); }, (err, value) => { if (err) console.log(err); console.log(value); // 10 });
Same as reduce, only operates on array in reverse order. 與reduce相似
...
排列順序(item / item * -1)
async.sortBy([13, 21, 321, 421, 3, 21, , , , 23121, 1], (item, callback) => { setTimeout(() => { callback(null, item * -1); // 從大到小 // callback(null, item); // 從小到大 }, 100); }, (err, value) => { if (err) console.log(err); console.log(value); }); // [23121, 421, 321, 21, 21, 13, undefined, undefined, undefined, 3, 1]
acc 意爲 accumulate,obj 則是 object
async.transform([1, 2, 3], (acc, item, index, callback) => { setTimeout(() => { acc.push(index + ': ' + item); callback(null); }, 100); }, (err, value) => { if (err) console.log(err); console.log(value); }); // ['0: 1', '1: 2', '2: 3']
對象的例子:
async.transform({ name: 'oli', age: 12 }, (obj, val, key, callback) => { setTimeout(() => { obj[key] = val + '...'; callback(null); }, 100); }, (err, value) => { if (err) console.log(err); console.log(value); }); // { name: 'oli...', age: '12...' }
If one of the tasks were successful, the callback will be passed the result of the successful task 一旦其中一個成功,則callback返回該成功的任務的返回值It runs each task in series but stops whenever any of the functions were successful. 測試哪一個成功
async.tryEach([ function getDataFromFirstWebsite(callback) { // Try getting the data from the first website callback(err, data); }, function getDataFromSecondWebsite(callback) { // First website failed, // Try getting the data from the backup website callback(err, data); } ], // optional callback function(err, results) { Now do something with the data. });
並行運行任務函數的數組,一旦任何一個完成或傳遞錯誤信息,主回調將當即調用。至關於 Promise.race()
async.race([ function(callback) { setTimeout(function() { callback(null, 'one'); }, 200); }, function(callback) { setTimeout(function() { callback(null, 'two'); // 優先觸發 }, 100); } ], // 主回調 function(err, result) { // the result will be equal to 'two' as it finishes earlier });
把f(),g(),h()異步函數,組合成f(g(h()))的形式
Each function consumes the return value of the function that follows
注意執行的順序,這裏的 add1mul3 即爲 先執行 mul3 而後執行 add1
function add1(n, callback) { setTimeout(function () { callback(null, n + 1); }, 10); } function mul3(n, callback) { setTimeout(function () { callback(null, n * 3); }, 10); } var add1mul3 = async.compose(mul3, add1); // 1) add1() 2) mul3() add1mul3(4, function (err, result) { console.log(result); // 15 });
Each function consumes the return value of the previous function. 與 compose 相似
pp.get('/cats', function(request, response) { var User = request.models.User; async.seq( _.bind(User.get, User), // 'User.get' has signature (id, callback(err, data)) function(user, fn) { user.getCats(fn); // 'getCats' has signature (callback(err, data)) } )(req.session.user_id, function (err, cats) { if (err) { console.error(err); response.json({ status: 'error', message: err.message }); } else { response.json({ status: 'ok', message: 'Cats found', data: cats }); } }); });
async.parallel([ async.apply(fs.writeFile, 'testfile1', 'test1'), async.apply(fs.writeFile, 'testfile2', 'test2') ]);
async.applyEach([enableSearch, updateSchema], 'bucket', callback);
only a single async operation at a time.
是一個串行的消息隊列,經過限制了worker數量,再也不一次性所有執行。當worker數量不夠用時,新加入的任務將會排隊等候,直到有新的worker可用
If all workers are in progress, the task is queued until one becomes available
queue(worker, concurrency)
concurrency 用來定義worker的數量
let q = async.queue(function (task, callback) { console.log('deal with ' + task.url); setTimeout(() => { axios({ methods: 'get', url: task.url }).then((d) => { console.log(d.data.length); callback(); }); }, 2000); }, 1); q.drain = function () { console.log('all done'); } q.push({ url: 'http://www.baidu.com' }, function (err) { if (err) { console.log(err); } }); q.unshift([{ url: 'http://www.baidu.com' }, { url: 'http://www.sogou.com' }], function (err) { if (err) { console.log(err); } }); // deal with http://www.sogou.com // 22430 // deal with http://www.baidu.com // 112041 // deal with http://www.baidu.com // 112220 // all done
與 queue 不一樣的是,push 能夠設置 priority push(task, priority, [callback])
While queue passes only one task to one of a group of workers at a time, cargo passes an array of tasks to a single worker, repeating when the worker is finished. queue 一個 worker 負責一個任務,但 cargo 則是一個 worker 負責一組任務。
// create a cargo object with payload 2 var cargo = async.cargo(function(tasks, callback) { for (var i=0; i<tasks.length; i++) { console.log('hello ' + tasks[i].name); } callback(); }, 2); // add some items cargo.push({name: 'foo'}, function(err) { console.log('finished processing foo'); }); cargo.push({name: 'bar'}, function(err) { console.log('finished processing bar'); }); cargo.push({name: 'baz'}, function(err) { console.log('finished processing baz'); });
瀏覽器使用 setImmediate
Calls callback on a later loop around the event loop
var call_order = []; async.nextTick(function () { call_order.push('two'); // 4 console.log(call_order); }); setTimeout(() => { call_order.push('four'); // 7 console.log(call_order); }, 100); async.nextTick(function () { call_order.push('three'); // 5 console.log(call_order); }); console.log(call_order); // 1 call_order.push('one'); // 2 console.log(call_order); // 3 async.setImmediate(function (a, b, c) { console.log(a, b, c); // 6 }, 1, 2, 3);
直接傳入同步方法:
async.waterfall([ async.apply(fs.readFile, './d.json', "utf8"), async.asyncify(JSON.parse), // 同步函數 function (data, next) { // 轉成異步 console.log(data) // data... next(data) // passing data... } ], (data) => { console.log(data); // data... });
包裹一層函數:
async.waterfall([ async.asyncify(function () { // 同步函數轉稱異步函數傳入參數須要用到一層function並return結果 return fs.readFileSync('./d.json', "utf8") }), function (data, next) { // 執行回調並調用 next console.log(data.length) next(data) }, async.asyncify(JSON.parse), function (data, next) { console.log(data) next(data) } ], (data) => { console.log(data); });
如asyncify的例子能夠修改成:
async.waterfall([ async.constant('./d.json', 'utf8'), // 設置參數 fs.readFile, // 調用參數 function (data, next) { console.log(data.length) next(data) }, async.asyncify(JSON.parse), function (data, next) { console.log(data) next(data) } ], (data) => { console.log(data); });
Logs the result of an async function to the console using console.dir to display the properties of the resulting object. 注意瀏覽器兼容性 console.dir 適用於 FireFox and Chrome
// in a module var hello = function(name, callback) { setTimeout(function() { callback(null, {hello: name}); }, 1000); }; // in the node repl node> async.dir(hello, 'world'); {hello: 'world'}
function sometimesAsync(arg, callback) { if (cache[arg]) { return callback(null, cache[arg]); // this would be synchronous!! } else { doSomeIO(arg, callback); // this IO would be asynchronous } } // this has a risk of stack overflows if many results are cached in a row async.mapSeries(args, sometimesAsync, done); // this will defer sometimesAsync's callback if necessary, // preventing stack overflows async.mapSeries(args, async.ensureAsync(sometimesAsync), done);
// in a module var hello = function(name, callback) { setTimeout(function() { callback(null, 'hello ' + name); }, 1000); }; // in the node repl node> async.log(hello, 'world'); 'hello world'
Caches the results of an async function. When creating a hash to store function results against, the callback is omitted from the hash and an optional hash function can be used.
var slow_fn = function(name, callback) { // do something callback(null, result); }; var fn = async.memoize(slow_fn); // fn can now be used as if it were slow_fn fn('some name', function() { // callback });
例如:
var slow_fn = function (url, callback) { axios({ methods: 'get', url }).then(e => { console.log(e.status) callback(null, e.data) }) }; var fn = async.memoize(slow_fn); fn('http://baidu.com', function (e, data) { console.dir('done') }); fn('http://sogou.com', function (e, data) { console.dir('done') }); // 200 // 'done' // 200 // 'done'
Undoes a memoized function, reverting it to the original
var call_order = []; async.nextTick(function() { call_order.push('two'); // call_order now equals ['one','two'] }); call_order.push('one'); async.setImmediate(function (a, b, c) { // a, b, and c equal 1, 2, and 3 }, 1, 2, 3);
always completes with a result object, even when it errors.
async.parallel([ async.reflect(function(callback) { // do some stuff ... callback(null, 'one'); }), async.reflect(function(callback) { // do some more stuff but error ... callback('bad stuff happened'); }), async.reflect(function(callback) { // do some more stuff ... callback(null, 'two'); }) ], // optional callback function(err, results) { // values // results[0].value = 'one' // results[1].error = 'bad stuff happened' // results[2].value = 'two' });
例如:
async.parallel([ async.reflect((callback) => { setTimeout(() => { callback('error') }, 1000) }), (callback) => { setTimeout(() => { callback(null, 'data') }, 2000) } ], (err, result) => { if (err) { console.error(err) } else { console.dir(result) // [ { error: 'error' }, 'data' ] } })
A helper function that wraps an array or an object of functions with reflect.
let tasks = [ function(callback) { setTimeout(function() { callback(null, 'one'); }, 200); }, function(callback) { // do some more stuff but error ... callback(new Error('bad stuff happened')); }, function(callback) { setTimeout(function() { callback(null, 'two'); }, 100); } ]; async.parallel(async.reflectAll(tasks), // reflectAll 包含了tasks任務列表 // optional callback function(err, results) { // values // results[0].value = 'one' // results[1].error = Error('bad stuff happened') // results[2].value = 'two' });
var call_order = []; async.nextTick(function() { call_order.push('two'); // call_order now equals ['one','two'] }); call_order.push('one'); async.setImmediate(function (a, b, c) { // a, b, and c equal 1, 2, and 3 }, 1, 2, 3);
Sets a time limit on an asynchronous function.If the function does not call its callback within the specified milliseconds, it will be called with a timeout error. 超過期間返回錯誤:'ETIMEDOUT'
function getData(url, callback) { axios({ methods: 'get', url }).then(d => { setTimeout(() => { return callback(null, d.status) }, 1000); }) } let wrappeed = async.timeout(getData, 1000) wrappeed('http://baidu.com', (err, data) => { if (err) { console.log(err) } else { console.log(data) } }) // { Error: Callback function "getData" timed out. // at Timeout.timeoutCallback [as _onTimeout] (/Users/apple/test/node_modules/_async@2.6.0@async/dist/async.js:4916:26) // at ontimeout (timers.js:386:14) // at tryOnTimeout (timers.js:250:5) // at Timer.listOnTimeout (timers.js:214:5) code: 'ETIMEDOUT' }