AsyncJS 異步流程控制DEMO詳細介紹

1. 基本流程

串行流程、並行流程、混合執行
series, waterfall; parallel, parallelLimit; auto;

1.1. 串行流程

1.1.1. series(多個函數依次執行,之間沒有數據交換)

有多個異步函數須要依次調用,一個完成以後才能執行下一個。各函數之間沒有數據的交換,僅僅須要保證其執行順序。這時可以使用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

1.1.2. waterfall(多個函數依次執行,且前一個的輸出爲後一個的輸入)

與seires類似,按順序依次執行多個函數。不一樣之處,每個函數產生的值,都將傳給下一個函數。若是中途出錯,後面的函數將不會被執行。錯誤信息以及以前產生的結果,將傳給waterfall最終的callback。web

注意,該函數不支持json格式的tasksjson

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'
});

1.2. 並行流程

1.2.1. parallel(多個函數並行執行)

並行執行多個函數,每一個函數都是當即執行,不須要等待其它函數先執行。傳給最終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}
});

1.2.2. parallelLimit(多個函數並行執行並限制同時執行的最大數量)

parallelLimit 與上面的 parallel 最大的不一樣就是限制最大同時執行的數量session

async.parallelLimit([(cb) => {
  setTimeout(() => {
    cb(null, 'one');
  }, 1000);
}, (cb) => {
  setTimeout(() => {
    cb(null, 'two');
  }, 2000);
}], 1, (err, value) => {
  log(value);
});
// 需時3s左右

1.3. 混合執行

1.3.1. auto(tasks, [callback]) (多個函數有依賴關係,有的並行執行,有的依次執行)

用來處理有依賴關係的多個任務的執行。好比某些任務之間彼此獨立,能夠並行執行;但某些任務依賴於其它某些任務,只能等那些任務完成後才能執行。

如異步獲取兩個數據並打印:

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' }

1.3.2. autoInject(tasks, callbackopt) (與auto相似但回調函數被做爲參數傳入下一個串行函數)

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' }
    }
})

2. 循環流程

2.1. whilst(用可於異步調用的while)

至關於while,但其中的異步調用將在完成後纔會進行下一次循環。舉例以下:

var count = 0;
async.whilst(
  () => { return count < 5; }, // 是否知足條件
  (callback) => { // 知足條件執行函數
    count++;
    setTimeout(() => {
      log(count)
      callback(null, count);
    }, 1000);
  },
  (err, value) => { // 不知足條件完成循環
    log('result: ' + count);
  }
);

2.2. doWhilst (後驗證的異步while)

首先執行函數

count = 0;
async.doWhilst((callback) => { // 先執行函數
  count++;
  setTimeout(() => {
    log(count);
    callback(null, count);
  }, 1000);
}, () => { // 後驗證條件
  return count < 5;
}, (err, value) => { // 主回調
  log('result: ' + count);
});

2.3. until (與while類似,但判斷條件相反)

var count = 0;
async.until(
  () => { return count >= 5; },
  (callback) => {
    count++;
    setTimeout(() => {
      log(count)
      callback(null, count);
    }, 1000);
  },
  (err, value) => {
    log('result: ' + count);
  }
);

2.4. doUntil (後驗證Until循環)

var count = 0;
async.doUntil(
  (callback) => { // 先執行
    count++;
    setTimeout(() => {
      log(count)
      callback(null, count);
    }, 1000);
  },
  () => { return count >= 5; }, // 後驗證
  (err, value) => {
    log('result: ' + count);
  }
);

2.5. during (相似whilst,回調判斷)

與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')
})

2.6. doDuring (相似doWhilst,回調判斷)

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');
    }
);

2.7. retry (按照頻率重複執行屢次直到成功位置)

在返回錯誤以前,嘗試從函數得到成功響應的次數不超過規定的次數。 若是任務成功,則回調將傳遞成功任務的結果。 若是全部嘗試都失敗,回調將傳遞最終嘗試的錯誤和結果。

async.retry({times: 3, interval: 200}, apiMethod, function(err, result) {
    log(result);
}); // 嘗試三次,間隔200,打印結果

2.8. retryable

包裝任務使其能夠retry

async.auto({
    dep1: async.retryable(3, getFromFlakyService),
    process: ["dep1", async.retryable(3, function (results, cb) {
        maybeProcessData(results.dep1, cb);
    })]
}, callback);

2.9. times (重複調用 n 次)

調用 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 ]
    }
})

2.10. timesLimit (與times相似,但可限制並行執行最大數量)

timesLimit(count, limit, iteratee, callback)

2.11. timesSeries (只可並行執行一個)

The same as times but runs only a single async operation at a time.
timesSeries(n, iteratee, callback)

2.12. forever (除非捕獲到錯誤,將容許一直執行——調用本身)

記得調用 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)
}

})

3. 集合流程

Async提供了不少針對集合的函數,能夠簡化咱們對集合進行異步操做時的步驟

3.1. each 集合中的元素執行函數

對全部集合中的全部元素,都執行同一個函數,並行:

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

3.2. eachLimit

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

3.3. eachOf/forEachOf

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

3.4. eachOfLimit/forEachOfLimit

The same as eachOf but runs a maximum of limit async operations at a time. 多個限制參數,再也不累述

3.5. eachOfSeries/forEachOfSeries

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

3.6. eachSeries/forEachSeries

至關於 eachLimit 限制爲 1

3.7. map 返回集合數據執行函數的結果集合

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]

3.8. mapLimit

與 map 類似,多了限制參數

3.9. mapSeries

至關於 mapLimit 限制 1

3.10. mapValues

用於處理對象

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 }

3.11. mapValuesLimit

多了限制參數

3.12. mapValuesSeries

至關於 mapValuesLimit 限制 1

3.13. filter 返回知足條件的原始元素

返回的是經過測試的原始數據,只有篩選,沒有修改原始數據

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']

3.14. filterLimit

...

3.15. filterSeries

...

3.16. reject 剔除知足條件的 (與filter相反)

與filter相反,經過驗證的,予以剔除

The opposite of filter. Removes values that pass an async truth test.

3.17. rejectLimit

...

3.18. rejectSeries

...

3.19. detect 第一個知足條件的

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

3.20. detectLimit

...

3.21. detectSeries

...

3.22. some/any 至少有一個符合條件的觸發主回調

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
});

3.23. someLimit/anyLimit

...

3.24. someSeries/anySeries

...

3.25. every/all 所有知足條件返回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
});

3.26. everyLimit/allLimit

...

3.27. everySeries/allSeries

...

3.28. concat 合併結果

將結果合併,一樣的,不能保證結果按照原來的順序排序
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 } ]

3.29. concatLimit

...

3.30. concatSeries

...

3.31. groupBy 結果根據對象的key分組

傳入一系列對象,並根據設置的 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' }]
// }

3.32. groupByLimit

...

3.33. groupBySeries

...

3.34. reduce 串行累加集合數據

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
});

3.35. reduceRight

Same as reduce, only operates on array in reverse order. 與reduce相似

...

3.36. srotBy 按順序排列

排列順序(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]

3.37. transform 經過某種規則轉化集合

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...' }

4. 其餘

4.1. tryEach ()

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.
});

4.2. race (哪一個優先結束)

並行運行任務函數的數組,一旦任何一個完成或傳遞錯誤信息,主回調將當即調用。至關於 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
});

4.3. compose (將多個異步函數串聯在一塊兒返回一個新的函數 相似 f(g(h())))

把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
});

4.4. seq

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 });
        }
    });
});

4.5. apply (給函數預綁定參數)

async.parallel([
    async.apply(fs.writeFile, 'testfile1', 'test1'),
    async.apply(fs.writeFile, 'testfile2', 'test2')
]);

4.6. applyEach

async.applyEach([enableSearch, updateSchema], 'bucket', callback);

4.7. applyEachSeries

only a single async operation at a time.

4.8. queue (串行的消息隊列)

是一個串行的消息隊列,經過限制了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

4.9. priorityQueue(worker, concurrency)

與 queue 不一樣的是,push 能夠設置 priority push(task, priority, [callback])

4.10. cargo (串行的消息隊列,每次負責一組任務)

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');
});

4.11. nextTick ()

瀏覽器使用 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);

4.12. asyncify (同步函數轉化成異步函數)

直接傳入同步方法:

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);
});

4.13. constant (通常用來給串行流程的下個階段傳值)

如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);
});

4.14. dir (調用console.dir)

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'}

4.15. ensureAsync (確保任務異步執行)

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);

4.16. log (調用console.log)

// 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'

4.17. memoize (緩存結果)

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'

4.18. unmemoize

Undoes a memoized function, reverting it to the original

4.19. nextTick

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);

4.20. reflect (遇到error繼續執行)

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' ]
    }
})

4.21. reflectAll (包裹reflect)

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'
});

4.22. setImmediate (瀏覽器中至關於 setTimeout(callback, 0))

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);

4.23. timeout (限制異步函數timeout最長延遲,時間過了返回錯誤)

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' }
相關文章
相關標籤/搜索