Node.jsの非同期関数を作成する方法


114

私は非同期関数がどのように書かれるべきかについて研究しようとしました。たくさんのドキュメンテーションを徹底的に調べた後、それは私にはまだ不明です。

Nodeの非同期関数を作成するにはどうすればよいですか?エラーイベント処理を正しく実装するにはどうすればよいですか?

私の質問をする別の方法はこれです:次の関数をどのように解釈すべきですか?

var async_function = function(val, callback){
    process.nextTick(function(){
        callback(val);
    });
};

また、SOでこの質問を見つけました(「node.jsで非ブロッキング非同期関数を作成するにはどうすればよいですか?」)は興味深いものです。まだ回答されていないようです。


14
それが私が求めている理由です。これらの機能がどのように異なるのか、私にはわかりません。
Kriem、2011

お気に入りのブラウザを見てsetTimeoutsetIntervalそれらをいじってみることをお勧めします。またはajaxコールバック(おそらくノードエクスペリエンスに最も近いもの)、またはクリックイベントやロードイベントなど、慣れ親しんだもののイベントリスナー。非同期モデルはブラウザにすでに存在しており、ノード内ではまったく同じです。
davin、2011

@davin-非同期モデルを完全には理解していないと思います。
Kriem

@Kriem、私は昨日役立つかもしれない何かに答えました:stackoverflow.com/questions/6883648/…それはあなたの質問に対する答えではありませんが、それはトピックに関するものです。質問を読んでそこに答え、コードをいじって何が起こっているのかを理解してください。
davin、2011

2
@Raynos「非同期関数」の定義は何ですか?
アンダーソングリーン

回答:


85

非同期IOと非同期関数を混同しているようです。非ブロッキングIOの方が優れているため、node.jsは非同期非ブロッキングIOを使用します。それを理解する最良の方法は、ライアン・ダールのいくつかのビデオを見に行くことです。

Nodeの非同期関数を作成するにはどうすればよいですか?

通常の関数を記述するだけです。唯一の違いは、それらはすぐには実行されず、コールバックとして渡されることです。

エラーイベント処理を正しく実装する方法

一般に、APIは最初の引数としてerrを使用してコールバックを提供します。例えば

database.query('something', function(err, result) {
  if (err) handle(err);
  doSomething(result);
});

一般的なパターンです。

別の一般的なパターンはon('error')です。例えば

process.on('uncaughtException', function (err) {
  console.log('Caught exception: ' + err);
});

編集:

var async_function = function(val, callback){
    process.nextTick(function(){
        callback(val);
    });
};

上記の関数は、

async_function(42, function(val) {
  console.log(val)
});
console.log(43);

印刷されます42非同期コンソールに。特にprocess.nextTick、現在のeventloopコールスタックが空になった後に発生します。その呼び出しスタックは空で実行されasync_functionconsole.log(43)います。したがって、43に続いて42を出力します。

あなたはおそらくイベントループでいくつかの読み取りを行う必要があります。


私はダールのビデオを見たことがありますが、私が心配している問題を把握しているようには見えません。:(
Kriem

1
@Kriem更新された回答を参照し、イベントループについて
レイノス

1
洞察をありがとう。今では知識が足りないことにもっと気づきました。:)ちなみに最後の例は助けになりました。
Kriem、2011

非同期IOについての記述は「優れている」とは一般的すぎると思います。そういう意味ではそうですが、全体としてはそうではないかもしれません。
ジェイクB

最初のコード例では、err引数を確認しましたが、後で戻りませんでした。エラーが発生した場合、コードは継続し、アプリケーションに重大な問題を引き起こす可能性があります。
ガブリエルマクアダムス2016年

9

コールバックを渡すだけでは十分ではありません。たとえば、関数を非同期にするには、settimerを使用する必要があります。

例:非同期ではない関数:

function a() {
  var a = 0;    
  for(i=0; i<10000000; i++) {
    a++;
  };
  b();
};

function b() {
  var a = 0;    
  for(i=0; i<10000000; i++) {
    a++;
  };    
  c();
};

function c() {
  for(i=0; i<10000000; i++) {
  };
  console.log("async finished!");
};

a();
console.log("This should be good");

上記の例を実行する場合、これは良いはずです。これらの関数が機能するまで、待たなければなりません。

疑似マルチスレッド(非同期)関数:

function a() {
  setTimeout ( function() {
    var a = 0;  
    for(i=0; i<10000000; i++) {
      a++;
    };
    b();
  }, 0);
};

function b() {
  setTimeout ( function() {
    var a = 0;  
    for(i=0; i<10000000; i++) {
      a++;
    };  
    c();
  }, 0);
};

function c() {
  setTimeout ( function() {
    for(i=0; i<10000000; i++) {
    };
    console.log("async finished!");
  }, 0);
};

a();
console.log("This should be good");

これは完全に非同期になります。これは、非同期が完了する前に書き込まれるのが良いでしょう。



3

関数がpromiseを返すことがわかっている場合は、JavaScriptの新しい非同期/待機機能を使用することをお勧めします。構文は同期的に見えますが、非同期的に動作します。asyncキーワードを関数に追加すると、awaitそのスコープでpromiseを実行できます。

async function ace() {
  var r = await new Promise((resolve, reject) => {
    resolve(true)
  });

  console.log(r); // true
}

関数がpromiseを返さない場合は、定義した新しいpromiseでラップしてから、必要なデータを解決することをお勧めします。

function ajax_call(url, method) {
  return new Promise((resolve, reject) => {
    fetch(url, { method })
    .then(resp => resp.json())
    .then(json => { resolve(json); })
  });
}

async function your_function() {
  var json = await ajax_call('www.api-example.com/some_data', 'GET');
  console.log(json); // { status: 200, data: ... }
}

結論:プロミスの力を活用します。


ここで覚えておくべきことは、promise本体は依然として同期的に実行されるということです。
shadow0359

2

これを試してください、それはノードとブラウザの両方で動作します。

isNode = (typeof exports !== 'undefined') &&
(typeof module !== 'undefined') &&
(typeof module.exports !== 'undefined') &&
(typeof navigator === 'undefined' || typeof navigator.appName === 'undefined') ? true : false,
asyncIt = (isNode ? function (func) {
  process.nextTick(function () {
    func();
  });
} : function (func) {
  setTimeout(func, 5);
});

18
4つの反対投票と建設的なコメントは1つもありません..:\
Omer

6
@OmerはSOでの生活です。
Piece Digital

6
@NorbertoBeziたぶんコードはあなたに自明ですが、答えを投稿した人にはわかりません。そのため、反対投票について説明することは常に良い習慣です。
2016年

0

node.jsでこのようなタスクを処理するのに時間がかかりすぎています。私は主にフロントエンドの人です。

すべてのノードメソッドは非同期でコールバックを処理し、それをPromiseに変換する方が処理しやすいため、これは非常に重要であると思います。

私は、可能な結果を​​より簡潔で読みやすい形で示したいと思っています。ECMA-6を非同期で使用すると、次のように記述できます。

 async function getNameFiles (dirname) {
  return new Promise((resolve, reject) => {
    fs.readdir(dirname, (err, filenames) => {
      err !== (undefined || null) ? reject(err) : resolve(filenames)
    })
  })
}

これ(undefined || null)repl用です(読み取りイベント印刷ループ)シナリオ用であり、未定義を使用しても機能します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.