PJCHENder 未整理筆記

[npm] AsyncJS

2017-12-24

[npm] AsyncJS

@(NodeJS)[npm, JavaScript]

keywords: aysnc

AsyncJS @ github

目錄

[TOC]

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 取得的元素;第二個是 AysnJS 中用的 callback

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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)
}

執行的結果會是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 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 function
10 finish function
4 finish function
3 finish function
1 finish function
5 finish function
9 finish function
6 finish function
8 finish function
7 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 執行結束後,才去執行下一個,因此結果會像下面這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# .mapSeries() 會把每一個 async function 執行完後才執行下一個:
1 invoke function at delayTime(110)
1 finish function
2 invoke function at delayTime(208)
2 finish function
3 invoke function at delayTime(978)
3 finish function
4 invoke function at delayTime(188)
4 finish function
5 invoke function at delayTime(523)
5 finish function
6 invoke function at delayTime(958)
6 finish function
7 invoke function at delayTime(537)
7 finish function
8 invoke function at delayTime(546)
8 finish function
9 invoke function at delayTime(671)
9 finish function
10 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)

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

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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()
}
}

執行結果如下:

1
2
3
4
5
6
7
8
9
10
----------------
Processing file app.js
File processed
----------------
Processing file thisisnewspaper.js
This file name is too long
A file failed to process
----------------
Processing file map.js
File processed

waterfall(tasks, callback)

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

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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)

1
2
3
4
5
6
async.waterfall([
async.constant(42),
function (value, next) {
// value === 42
},
], callback);

parallel(tasks, callback)

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

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* tasks 以陣列的方式代入
* async.paraller([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)
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* tasks 以物件帶入,結果會根據 callback 的完成的時間排序
* async.paraller({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 }
});

掃描二維條碼,分享此文章