首頁 >web前端 >js教程 >JavaScript非同步程式設計:非同步資料收集的具體方法_javascript技巧

JavaScript非同步程式設計:非同步資料收集的具體方法_javascript技巧

WBOY
WBOY原創
2016-05-16 17:25:131069瀏覽

Asyncjs/seriesByHand.js

複製程式碼 程式碼如下:

var fs = require('fs');

var fs = require('fs');


var fs = require('fs');



var fs = require('fs');

var fs = require('fs'); >process.chdir('recipes'); // 改變工作目錄

var concatenation = '';

fs.readdir('.', function(err, filenames) {
  if (err) throw err;

  function readFileAt(i) {
    var filename = filenames[i];
    fs.stat(filename, function(err, statT) {
      fs.readFile(filename, 'utf8', function(err, text) {
        if (err) throw  i 1 === filenames.length ) {
          // 皆已讀取,且可顯示輸出  1);
      });

});

  }

  readFileAt(0);});

如你所見,非同步版本的程式碼比同步版本多得多。如果使用filter、forEach這些同步方法,程式碼的行數大約只有一半,而且讀起來也要容易得多。如果這些漂亮的迭代器存在非同步版本該有多好啊!使用Async.js就能做到這一點!

 

何時拋出亦無妨?

大家可能注意到了,在上面那個程式碼範例中筆者無視了自己在第1.4節中提出的建議:從回調中拋出異常是一種糟糕的設計,尤其在成品環境中。不過,一個簡單如斯的範例直接拋出異常則完全沒有問題。如果真的遇到程式碼出錯的意外情形,throw會關閉程式碼並提供一個漂亮的堆疊軌跡來解釋出錯原因。

這裡真正的不妥之處在於,同樣的錯誤處理邏輯(即if(err) throw err)重複了多達3次!在4.2.2節,我們會看到Async.js如何幫助減少這種重複。


Async.js的函數式寫法
我們想把同步迭代器所使用的filter和forEach方法替換成對應的非同步方法。 Async.js給了我們兩個選擇。

async.filter和async.forEach,它們會並行處理給定的陣列。
async.filterSeries和async.forEachSeries,它們會依序處理給定的陣列。
並行運行這些非同步操作應該會更快,那為什麼還要使用序列式方法呢?原因有兩個。

前面提到的工作流程次序不可預測的問題。我們確實可以先把結果儲存成數組,然後再joining(聯接)數組來解決這個問題,但這畢竟多了一個步驟。

Node及其他任何應用程式能夠同時讀取的檔案數量有一個上限。如果超過這個上限,作業系統就會報錯。如果能順序讀取文件,則無需擔心此限制。

所以現在先搞清楚async.forEachSeries再說。下面使用了Async.js的資料收集方法,直接改寫了同步版本的程式碼實作。

Asyncjs/forEachSeries.js
複製程式碼


程式碼如下:

var async = require('async');var fs = require('fs');

process.chdir('recipes'); // 改變工作目錄

var concatenation = '';


var dirContents = fs.readdirSync('.');

async.filter(dirContents, isFilename, function(filenames) {

  async.forEachSeries(filenames, readAndConcat, onComplete);
});

function isFilename(filename, callback) {
  fs.stat(filename, function(err, stats) {
    if (err) throw err;

🎜>  });

}

function readAndConcat(filename, callback) {
  fs.readFile(filename, 'utf8', function(err, fileContents) {
    if (err) return callback(err);    callback();
  });

}


function onComplete(err) {
  if (err) throw err;
  console.log(concatenation);

}

これで、私たちのコードは 2 つの部分に見事に分割されました: タスクの概要 (async.filter 呼び出しと async.forEachSeries 呼び出しの形式) と実装の詳細 (2 つのイテレーター関数と完了コールバック onComplete の形式)。

標準の関数反復メソッドに対応する Async.js ユーティリティ関数は、

filter と forEach だけではありません。 Async.js は次のメソッドも提供します:

reject/rejectSeries、フィルターの逆、
map/mapSeries、1:1 変換、
reduce/reduceRight、値の段階的な変換。フィルター;
sortBy、順序付けされたコピーを作成します。
some、少なくとも 1 つの値が指定された基準を満たすかどうかをテストします。
every、すべての値が指定された基準を満たすかどうかをテストします。
これらのメソッドは Async.js の本質であり、コードの重複を最小限に抑えながら一般的な反復作業を実行できるようにします。より高度なメソッドの検討を続ける前に、これらのメソッドのエラー処理手法を見てみましょう。

Async.js エラー処理テクノロジー

それを責めたいなら、これを最初に実行した Node の fs.exists を責めてください。これは、Async.js データ収集メソッド (filter/filterSeries、reject/rejectSeries、detect/detectSeries、some、every など) を使用するイテレーターがエラーを報告できないことも意味します。

ブール値ではないすべての Async.js イテレータの場合、イテレータ コールバックの最初のパラメータとして非 null/未定義値を渡すと、エラー値を使用して完了コールバックが即座に呼び出されます。これが、readAndConcat が throw なしで動作する理由です。

Asyncjs/forEachSeries.js

コードをコピー コードは次のとおりです。
function readAndConcat(filename, callback) {
fs .readFile(filename, 'utf8', function(err, fileContents) {
if (err) return callback(err);
concatenation = fileContents;
callback();
} );
}

したがって、callback(err) が readAndConcat で実際に呼び出された場合、この err は完了コールバック (つまり、onComplete) に渡されます。 Async.js は、onComplete が最初のエラーによって呼び出されたのか、すべての操作が正常に完了したときに呼び出されたのかに関係なく、onComplete が 1 回だけ呼び出されるようにすることのみを担当します。
Asyncjs/forEachSeries.js

コードをコピーします コードは次のとおりです。
function onComplete(err) {
if (err ) throw err;
console.log(concatenation);
}

ノードのエラー処理規則は、Async.js データ収集メソッドには理想的ではないかもしれませんが、Async には理想的ではありません。 js の他のすべてのメソッドと同様に、これらの規則に従うことで、エラーが各タスクから完了コールバックにきれいに流れることができます。次のセクションで、この例をさらに見ていきます。
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn