49

すべての JavaScript コールバックが非同期なのか、それとも特定の状況でのみ非同期なのかについて興味があります。また、javascriptコードを非同期にするもの(または非同期javascriptを使用する方法)がブラウザとnodejsで異なると確信しているので、それぞれの状況で実際の非同期javascriptを構成するものを知りたい.

次のシナリオでは、実際には非同期コードを書いていないという印象を受けています。

function addOne(value){
  value = value + 1;
  return value;
}

function simpleMap(values, callback){
  for(i = 0; i < values.length; i++){
    val = values[i];
    val = callback(val);
    values[i] = val;
  }
  return values;
}

newValues = simpleMap([1,2,3], addOne);

ただし、たとえば、jQuery の AJAX 関数が真に非同期であることはわかっています (現在利用可能なプロミスは考慮していません)。jQuery の AJAX を非同期にするのは何ですか? XHR リクエストが関係するのと同じくらい単純で、ブラウザではすべての XHR リクエストが非同期ですか?

nodejs環境についても同じ質問があります。ファイル i/o、process.nextTick、setTimeout、または setInterval のようなものが含まれる場合にのみ、ノード内の何かを非同期にすることができますか? mongodb/mongoose を使用してデータベース呼び出しのようなことを行うと、それが非同期になるのはなぜですか? それを可能にしている舞台裏で何が起こっているのでしょうか?

非同期の「状況」は環境によって事前に決定されていますか? または、環境の非常に特定の機能 (xhr、ノード内のファイル io、process.nexttick など) を利用せずに、独自の機能を真に非同期にする方法はありますか?

4

5 に答える 5

53

すべての JavaScript コールバックが非同期かどうかについて知りたい

いいえ。たとえば、 で使用されるコールバックArray#sortは非同期ではなく、 で使用されるものでもありませんString#replace

コールバックが非同期かどうかを知る唯一の方法は、そのドキュメントを参照することです。通常、外部リソースへのリクエスト (たとえば、ajax 呼び出し) を伴うものは非同期であり、他のものはそうである場合とそうでない場合があります。

ただし、たとえば、jQuery の AJAX 関数が本当に非同期であることは知っています...

現在、jQuery には、同期要求を強制するためにasync設定できるフラグがまだあるため、必ずしもそうではありません。false(それは良い考えではありません。彼らはそれを削除しようとしていますが、できます.jQueryは、同期/非同期動作を提供する基礎となるブラウザオブジェクトにフラグを渡します。)

jQuery の AJAX を非同期にするのは何ですか?

ブラウザ。jQuery の ajax 呼び出しはXMLHttpRequestオブジェクト (または特定の状況ではscript要素) を使用します。これは、ブラウザーによって提供される非同期操作にデフォルト設定されます。

または、環境の非常に特定の機能を活用せずに、独自の機能を真に非同期にする方法はありますか...

最近まで、いいえ。第 5 版の仕様まで、JavaScript言語はスレッドと非同期性の概念全体について基本的に沈黙していました。それが出てきたのは、環境に入ったときだけでした。何かを非同期にする唯一の方法は、ホストが提供する関数nextTick(または非同期で完了するさまざまな操作のいずれか) を NodeJS またはsetTimeoutブラウザーで使用することでした。

2015 年 6 月の ECMAScript 第 6 版仕様で、言語にpromiseが導入されました。thenなどを介して ES6 promise に接続されたコールバックは常に非同期で呼び出されます (コールバックがアタッチされたときに promise が既に解決されていても)、JavaScript は言語レベルで非同期性を備えています。したがって、コールバックを受け入れるのではなく promise を返すように関数を実装すると、関数にthen接続されたコールバックが非同期でトリガーされることがわかります。

于 2013-09-29T21:19:05.077 に答える
14

自分で呼び出すコールバックは通常の関数呼び出しであり、常に同期的です。

特定のネイティブ API (AJAX、ジオロケーション、Node.js ディスクまたはネットワーク API など) は非同期であり、後でイベント ループでコールバックを実行します。

非同期コールバック内からコールバックを同期的に呼び出すと、それも非同期になります。

于 2013-09-29T21:19:27.147 に答える
12

独自の非同期関数を作成するには、インタープリターによって提供される可能性のある他の非同期関数を利用する必要があります。

たとえば、このコードは、非同期の関数「addKeyHandler」を定義しています。しかし、それが機能するのは、document.onKey が JS エンジンによって非同期的に呼び出されるためです。JavaScript エンジンは非同期機能を提供できます。これは、オペレーティング システムが提供する機能が JS によって使用されるためです。OS は、ハードウェアが非同期機能を提供するため (ハードウェア割り込みと呼ばれます)、非同期機能のみを提供できます。

ただし、OS とハードウェアが非同期関数を提供していない場合でも、JS インタープリターを作成することは可能です。ただし、無限ループを使用し、イベントが発生したかどうかを反復ごとにチェックしてから、適切なコールバックを呼び出す必要があります。これは、CPU が常に全負荷状態にあることを意味します。

var keyCallbacks = [];

var addKeyHandler = function(f) {
  keyCallbacks.push(f);
};

document.onkeypress = function(e) {
  keyCallbacks.forEach(function(f) {
      f(e);
  });
};

addKeyHandler(function(e) {
    console.log(String.fromCharCode(e.charCode));
});
于 2013-09-29T22:22:13.777 に答える
1

コールバックを取得するだけでは、関数は非同期になりません。関数の引数を取るが非同期ではない関数の例は多数あります。たとえば、ArrayforEachです。

関数を非同期にするためには、非同期操作を実行する必要があります。非同期性を導入する方法は次のとおりです。

  • タイマー機能setTimeout,setInterval
  • 特殊機能nextTick,setImmediate
  • I/O の実行 (ネットワークのリッスン、データベースのクエリ、リソースからの読み取りまたは書き込み)
  • イベントの購読

記事によると、「コールバックを取得すると関数が非同期になりますか?」

于 2016-03-14T11:43:09.730 に答える