Skip to main content

[note] AsyncJS 筆記

keywords: async#

AsyncJS @ github

API#

map(coll, iteratee, callback<err, results>)#

  • mapSeries(coll, iteratee, callback<err, results>):用法和 .map() 的用法一樣,差別在於會在前一個 async function 執行結束後,才去執行下一個。
  • mapLimit(coll, limit, iteratee, callback<err, results>):用法和 .map() 的用法一樣,差別在於可以設定一次要非同步執行的數量。

這個函式會平行地執行透過 iteratee 帶入 coll 中的項目,而 iteratee 是非同步的方法,因此並不保證會照順序執行,但是最後的結果會照著 coll 的順序加以排列。

例子(map)#

iteratee 這個 function 會包含兩個參數,第一個是從陣列 paths 取得的元素;第二個是 AsyncJS 中用的 callback

const async = require('async');const fs = require('fs');
let paths = Array.from({ length: 10 }, (val, index) => index + 1); // [1, 2, 3, ..., 10]
/** * 陣列 paths 中的每一個元素的會執行 getPathName 這個函式 * 並且在全部執行完後,執行 map 最後面的 callback function **/async.map(paths, getPathName, function (err, results) {  // results 會是所有 getPathName 中透過 callback 傳回來的內容  console.log(results);});
/** * getPathName 帶有兩個參數 * 第一個參數:陣列的元素 * 第二個參數: AsyncJS 中的 callback<err, result>,透過這個 callback 可以把結果丟回去 **/function getPathName(path, callback) {  var delayTime = Math.floor(Math.random() * (1000 - 100 + 1)) + 100;  console.log(`${path} invoke function at delayTime(${delayTime})`);
  setTimeout(function () {    console.log(path + ' finish function');    // 把執行後的結果丟回去主要的 map function    callback(null, `get path: ${path}`);  }, delayTime);}

執行的結果會是:

# getPathName 會依照給入的元素順序執行1 invoke function at delayTime(447)2 invoke function at delayTime(152)3 invoke function at delayTime(428)4 invoke function at delayTime(414)5 invoke function at delayTime(470)6 invoke function at delayTime(861)7 invoke function at delayTime(998)8 invoke function at delayTime(978)9 invoke function at delayTime(721)10 invoke function at delayTime(314)
# 但因為是非同步函式,所以每個函式完成的時間順序不同2 finish function10 finish function4 finish function3 finish function1 finish function5 finish function9 finish function6 finish function8 finish function7 finish function
# results 最終的結果會按照陣列元素的順序來排列[ 'get path: 1',  'get path: 2',  'get path: 3',  'get path: 4',  'get path: 5',  'get path: 6',  'get path: 7',  'get path: 8',  'get path: 9',  'get path: 10' ]

例子(mapSeries)#

.mapSeries() 的用法和 .map() 的用法一樣,唯一的差別在於 .mapSeries() 會在前一個 async function 執行結束後,才去執行下一個,因此結果會像下面這樣:

# .mapSeries() 會把每一個 async function 執行完後才執行下一個:1 invoke function at delayTime(110)1 finish function2 invoke function at delayTime(208)2 finish function3 invoke function at delayTime(978)3 finish function4 invoke function at delayTime(188)4 finish function5 invoke function at delayTime(523)5 finish function6 invoke function at delayTime(958)6 finish function7 invoke function at delayTime(537)7 finish function8 invoke function at delayTime(546)8 finish function9 invoke function at delayTime(671)9 finish function10 invoke function at delayTime(527)10 finish function
# results[ 'get path: 1',  'get path: 2',  'get path: 3',  'get path: 4',  'get path: 5',  'get path: 6',  'get path: 7',  'get path: 8',  'get path: 9',  'get path: 10' ]

each(coll, iteratee, callback[opt])#

coll 中的每個元素以平行處理的方式套用到 iteratee<arg, cb> 這個 function 中,因為是平行處理的方式(in parallel),所以不保證執行的順序。

例子#

const async = require('async');let files = ['app.js', 'thisisnewspaper.js', 'map.js'];
// async.each(coll, iteratee<item, cb>, callback<err>)async.each(files, processFile, (err) => {  if (err) {    console.log('A file failed to process');  } else {    console.log('All files have been processed successfully');  }});
// iteratee<item, cb>function processFile(file, callback) {  console.log('Processing file ' + file);
  if (file.length > 10) {    console.log('This file name is too long');    callback('File name too long');  } else {    console.log('File processed');    callback();  }}

執行結果如下:

----------------Processing file app.jsFile processed----------------Processing file thisisnewspaper.jsThis file name is too longA file failed to process----------------Processing file map.jsFile processed

waterfall(tasks, callback[opt])#

以順序的方式執行 tasks,並且把執行的結果,透過 callback(null, para) 帶到下一個函式中。

例子#

const async = require('async');
async.waterfall([myFirstFunction, mySecondFunction, myLastFunction], function (err, result) {  if (err) {    throw new Error(err);  }  console.log('result', result); // done});
function myFirstFunction(callback) {  callback(null, 'one', 'two');}
function mySecondFunction(arg1, arg2, callback) {  console.log(arg1, arg2); // one, two  callback(null, 'three');}
function myLastFunction(arg1, callback) {  console.log(arg1); // three  callback(null, 'done');}

如果 waterfall 中的第一個函式想要代入變數,可以是用 async.constant(argument)

async.waterfall(  [    async.constant(42),    function (value, next) {      // value === 42    },  ],  callback,);

parallel(tasks, callback[opt])#

當所有的 tasks 都完成後才會執行 callback 中的內容。

例子#

/** * tasks 以陣列的方式代入 * async.parallel([fn<cb>, fn<cb>], callback<err, results>) **/async.parallel(  [    function (callback) {      setTimeout(function () {        callback(null, 'one');      }, 2000);    },    function (callback) {      setTimeout(function () {        callback(null, 'two');      }, 100);    },  ],
  function (err, results) {    // 結果會是 ['one', 'two'] 即使第二個 function 的 timeout 時間較短    console.log(results);  },);
/** * tasks 以物件帶入,結果會根據 callback 的完成的時間排序 * async.parallel({one: fn<cb>, two: fn<cb>}, callback<err, results>) **/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:    console.log(results)    // { two: 2, one: 1 }});