ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript で非同期がどのように処理されるかを理解する

JavaScript で非同期がどのように処理されるかを理解する

青灯夜游
青灯夜游転載
2020-11-20 17:29:059355ブラウズ

JavaScript で非同期がどのように処理されるかを理解する

Web サイト開発では、非同期イベントはプロジェクトが対処しなければならないリンクです。また、フロントエンド フレームワークの台頭により、フレームワークを介して実装された SPA が Web サイトを迅速に構築するための標準になりました. データの取得は必須となってきましたが、今回はJavaScriptにおける非同期処理についてお話します。

同期しますか?非同期ですか?

まず第一に、もちろん、同期と非同期がそれぞれ何を指すのかを理解する必要があります。

これら 2 つの用語は初心者にとって常に混乱を招きます。結局のところ、中国語の文字通りの意味は逆に理解するのが簡単です。情報科学の観点から見ると、同期とは物事を 1 つずつ実行することを指しますが、非同期とは次のことを指します多くのことが並行して一緒に処理されます。

例えば、銀行に行って用事を済ませる場合、窓口の前に並ぶのが同期実行、番号を取得して他のことを先に行うのが非同期実行というように、イベントループの特性により非同期実行が行われます。イベントは JavaScript で表現できます。それは簡単です。

それでは、JavaScript で非同期イベントを処理する方法は何でしょうか?

コールバック関数

私たちが最もよく知っているコールバック関数は、callback 関数です。たとえば、Web ページがユーザーと対話するときに登録されるイベント リスナーはコールバック関数を受け取る必要があります。また、setTimeoutxhr などの他の Web API のさまざまな関数も渡すことができます。ユーザーが要求した時間にトリガーするコールバック関数を渡します。まず setTimeout の例を見てみましょう:

// callback
function withCallback() {
  console.log('start')
  setTimeout(() => {
    console.log('callback func')
  }, 1000)
  console.log('done')
}withCallback()
// start
// done
// callback func

setTimeout が実行された後、指定された時間が経過すると、コールバック関数が最後に配置されます。キューの を削除し、イベント ループがそれを処理するのを待ちます。

注: この仕組みにより、開発者が setTimeout に設定した時間間隔は、実行からトリガーまでの経過時間と正確には一致しません。使用する場合は注意してください。注意!

コールバック関数は開発において非常に一般的ですが、回避が難しい問題も数多くあります。たとえば、関数を他の関数に渡す必要があるため、開発者が他の関数の処理ロジックを制御するのは困難です。また、コールバック関数はエラーをキャッチするために try...catch と連携することしかできないためです。 、非同期エラーが発生した場合の制御は困難であり、さらに、最も有名な「コールバック地獄」があります。

Promise

幸いなことに、Promise は ES6 の後に登場し、地獄に陥った開発者を救いました。その基本的な使用法も非常に簡単です:

function withPromise() {
  return new Promise(resolve => {
    console.log('promise func')
    resolve()
  })
}
withPromise()
  .then(() => console.log('then 1'))
  .then(() => console.log('then 2'))
// promise func
// then 1
// then 2

以前にイベント ループについて説明したときに言及されなかったのは、HTML 5 Web API 標準では、イベント ループはマイクロ タスク キューを追加し、Promise It はマイクロタスクによって駆動されるということです。キュー; マイクロタスク キューのトリガー時間はスタックがクリアされたときです。JavaScript エンジンはまずマイクロタスク キューに何かがあるかどうかを確認します。何かある場合は、それが最初に実行され、それが完了するまでキューから取得されません。新しいタスクをスタックにポップします。

上記の例のように、関数が Promise を返すと、JavaScript エンジンは後で渡された関数をマイクロタスク キューに入れ、繰り返しループし、上記の結果を出力します。後続の .then 構文は新しい Promise を返し、パラメーター関数は前の Promise.resolve の結果を受け取ります。この関数パラメーター転送を使用すると、開発者は非同期イベントをパイプライン処理できます。順次。

例に setTimeout を追加すると、マイクロタスクと一般タスクの違いがより明確に理解できます。

function withPromise() {
  return new Promise(resolve => {
    console.log('promise func')
    resolve()
  })
}
withPromise()
  .then(() => console.log('then 1'))
  .then(() => setTimeout(() => console.log('setTimeout'), 0))
  .then(() => console.log('then 2'))
// promise func
// then 1
// then 2 -> 微任务优先执行
// setTimeout

さらに、上記のコールバック関数は難しいです。非同期エラーを処理するには、.catch 構文を使用してキャプチャすることもできます。

function withPromise() {
  return new Promise(resolve => {
    console.log('promise func')
    resolve()
  })
}
withPromise()
  .then(() => console.log('then 1'))
  .then(() => { throw new Error('error') })
  .then(() => console.log('then 2'))
  .catch((err) => console.log('catch:', err))
// promise func
// then 1
// catch: error
//   ...error call stack

async await

ES6 Promise の出現以来、非同期コードはコールバック地獄からエレガントな関数型パイプライン処理へと徐々に変化してきました。開発者にとっては、コールバック地獄からプロミス地獄に変わるだけです。

新しい async/await は ES8 で標準化され、Promise と Generator Function を組み合わせるための単なる糖衣構文ですが、async# を経由します。 # #/await そうすれば、古い木に新しい花が咲くように、非同期イベントを同期構文で処理できるようになります。書き方は Promise とはまったく異なります:

function wait(time, fn) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('wait:', time)
      resolve(fn ? fn() : time)
    }, time)
  })
}
await wait(500, () => console.log('bar'))
console.log('foo')
// wait: 500
// bar
// foo
By

setTimeout は Promise にパッケージ化され、 await キーワードで呼び出されます。結果は、最初に bar 、次に foo が同期的に実行されることがわかります。つまり、冒頭で述べた同期処理に非同期イベントを書き込むことです。

別の例を見てください:

async function withAsyncAwait() {
  for(let i = 0; i < 5; i++) {
    await wait(i*500, () => console.log(i))
  }
}await withAsyncAwait()
// wait: 0
// 0
// wait: 500
// 1
// wait: 1000
// 2
// wait: 1500
// 3
// wait: 2000
// 4
コードは、

for ループと await を使用して、withAsyncAwait 関数を実装します。キーワード wait 関数を繰り返し実行します。ここで実行すると、ループは次のループを実行する前に、順番に異なる秒数待機します。

async/await を使用する場合、await キーワードは非同期関数内でのみ実行できるため、必ず次の場所で使用することを忘れないでください。同時に。

さらに、ループを使用して非同期イベントを処理する場合、ES6 以降に提供される多くの Array メソッドは async/await 構文をサポートしていないことに注意する必要があります。ここで ##forEach# を ##for に置き換えると、結果は同期実行となり、0.5 秒ごとに数値が出力されます。 ##この記事では、JavaScript が処理する 3 つの非同期処理方法を簡単に紹介し、いくつかの簡単な例を使用してコードの実行順序を説明します。前述のイベント ループをエコーし​​、それにマイクロタスク キューの概念が追加されています。同期アプリケーションと非同期アプリケーションを理解するのに役立つことを願っています。 プログラミング関連の知識について詳しくは、

プログラミング入門

をご覧ください。 !

以上がJavaScript で非同期がどのように処理されるかを理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。