1 つの記事で Node.js の非同期プログラミングを学ぶ

1 つの記事で Node.js の非同期プログラミングを学ぶ

目次 はじめに 同期 非同期とブロッキング JavaScript のノンブロッキング コールバック コールバック関数のエラー処理 コールバック地獄 ES6 の Promise Promise とは Promise の機能 Promise の利点 Promise の欠点 Promise の使い方 Promise の実行順序 async と await async の実行順序 async の機能のまとめ

導入

JavaScript はデフォルトでシングルスレッドであるため、コードは並列実行するための新しいスレッドを作成できません。しかし、ブラウザで最初に実行された JavaScript の場合、シングルスレッドの同期実行環境では、ページのクリックやマウスの移動など、ユーザー応答機能のニーズを満たすことができませんでした。そのため、ブラウザは、JavaScript がコールバック方式でページ要求イベントに非同期的に応答できるようにする一連の API を実装しました。

さらに、NodeJS は非ブロッキング I/O を導入し、非同期の概念をファイル アクセスやネットワーク呼び出しなどに拡張しました。

今日は、さまざまな非同期プログラミングの利点、欠点、開発の傾向について詳しく見ていきます。

同期、非同期、ブロッキング、非ブロッキング

Node.js の非同期プログラミングについて説明する前に、混同されやすい概念、つまり同期、非同期、ブロッキング、非ブロッキングについて説明しましょう。

いわゆるブロッキングとノンブロッキングとは、プロセスまたはスレッドが操作を実行したり、データの読み書きをするときに待機する必要があるかどうか、および待機プロセス中に他の操作を実行できるかどうかを指します。

待機が必要で、スレッドまたはプロセスが待機プロセス中に他の操作を実行できず、ただ待機することしかできない場合、この操作はブロックされていると言います。

逆に、プロセスまたはスレッドが操作を実行したり、データの読み取りや書き込みを行ったりしながら他の操作を実行できる場合、その操作は非ブロッキングであると言えます。

同期と非同期は、データにアクセスする方法を指します。同期とは、データをアクティブに読み取る必要があることを意味し、この読み取りプロセスはブロッキングまたは非ブロッキングになります。非同期とは、データを積極的に読み取る必要がなく、受動的な通知であることを意味します。

明らかに、JavaScript のコールバックは受動的な通知であり、非同期呼び出しと呼ぶことができます。

JavaScript のコールバック

JavaScript のコールバックは、非同期プログラミングの非常に典型的な例です。

document.getElementById('button').addEventListener('click', () => {
 console.log('ボタンがクリックされました!');
})

上記のコードでは、ボタンにクリック イベント リスナーを追加しました。クリック イベントがリッスンされると、コールバック関数がトリガーされ、対応する情報が出力されます。

コールバック関数は、addEventListener にパラメーターとして渡され、イベントがトリガーされたときにのみ呼び出される点を除いて、通常の関数と同じです。

前回の記事で説明した setTimeout と setInterval は、実際には非同期コールバック関数です。

コールバック関数でのエラー処理

Node.js でコールバックエラー情報を処理するにはどうすればよいですか? Nodejs は非常に巧妙な方法を使用します。Nodejs では、コールバック関数の最初のパラメータはエラー オブジェクトです。このエラー オブジェクトが存在するかどうかを判断することで、対応するエラー処理を実行できます。

fs.readFile('/文件.json', (err, data) => {
 (エラー!== null)の場合{
 //エラーを処理する console.log(err)
 戻る
 }

 // エラーがなければデータを処理します。
 コンソール.log(データ)
})

コールバック地獄

JavaScript コールバックは優れていますが、同期処理の問題を効果的に解決します。しかし残念なことに、次のステップを実行するためにコールバック関数の戻り値に頼る必要がある場合、このコールバック地獄に陥ってしまいます。

これをコールバック地獄と呼ぶのは少し大げさですが、コールバック関数の問題をある側面から反映しているとも言えます。

fs.readFile('/a.json', (err, データ) => {
 (エラー!== null)の場合{
 fs.readFile('/b.json',(err,data) => {
  //コールバック内のコールバック
 })
 }
})

どうすれば解決できるでしょうか?

ES6 で Promise が導入され、ES2017 で Async/Await が導入されたので、この問題を解決できると心配する必要はありません。

ES6 の Promise

約束とは何ですか?

Promise は非同期プログラミングのソリューションであり、「コールバック関数とイベント」という従来のソリューションよりも合理的で強力です。

いわゆる Promise は、将来終了するイベント (通常は非同期操作) の結果を格納する単なるコンテナーです。

構文的には、Promise は非同期操作に関するメッセージを取得できるオブジェクトです。

プロミスの特徴

Promise には 2 つの特性があります。

オブジェクトの状態は外界の影響を受けません。

Promise オブジェクトは非同期操作を表し、Pending (進行中)、Resolved (完了、Fulfilled とも呼ばれる)、および Rejected (失敗) の 3 つの状態を持ちます。

非同期操作の結果のみが現在の状態を決定し、他の操作ではこの状態を変更できません。

一度状態が変化すると、再び変化することはなく、いつでも結果を得ることができます。

Promise オブジェクトの状態が変化する可能性は、Pending から Resolved へ、または Pending から Rejected への 2 つだけです。

これはイベントとは全く違います。イベントは聞き逃したら何も得られないという特性があります。

約束の利点

Promise は、ネストされたコールバック関数を回避して、非同期操作を同期操作の形式で表現します。

Promise オブジェクトは、非同期操作の制御を容易にする統一されたインターフェースを提供します。

約束のデメリット

  1. Promise はキャンセルできません。作成されるとすぐに実行され、途中でキャンセルすることはできません。
  2. コールバック関数が設定されていない場合、Promise 内でスローされたエラーは外部に反映されません。
  3. 保留中状態の場合、プロジェクトが現在どの段階にあるか (開始したばかりか、完了間近か) を知ることはできません。

Promiseの使用法

Promise オブジェクトは、Promise インスタンスを生成するコンストラクターです。

var promise = new Promise(function(resolve, reject) { 
// ... コード 
if (/* 非同期操作が成功しました*/){ 
解決(値); 
} そうでない場合は{ 拒否(エラー); } 
}
);

Promise は then 操作に接続でき、then 操作は 2 つの関数パラメータに接続できます。最初の関数パラメータは Promise の構築時に解決された値であり、2 番目の関数パラメータは Promise を拒否したエラーです。

promise.then(関数(値) { 
// 成功 
}, 関数(エラー) { 
// 失敗 }
);

具体的な例を見てみましょう。

関数タイムアウト(ms){
 新しい Promise を返します(((resolve, reject) => {
  setTimeout(解決、ミリ秒、'完了');
 }))
}

タイムアウト(100)。その後(値 => console.log(値));

Promise で setTimeout メソッドが呼び出され、固定の時間に resolve メソッドがトリガーされ、パラメータ done が渡されます。

最後に、プログラムは done を出力します。

約束の実行順序

Promise が作成されると、すぐに実行されます。ただし、Promise.then のメソッドは、呼び出しサイクルが経過するまで待機してから再度呼び出します。次の例を見てみましょう。

promise = new Promise(((resolve, deny) => { とする
 console.log('ステップ1');
 解決する();
}));

promise.then(() => {
 console.log('ステップ3');
});

console.log('ステップ2');

出力:
ステップ1
ステップ2
ステップ3

非同期と待機

もちろん、Promise は素晴らしいです。コールバック地獄をチェーン呼び出しに変換します。 then を使用して複数の Promise を接続し、前の Promise の解決の結果が次の Promise の then のパラメーターになります。

チェーンコールの欠点は何ですか?

たとえば、Promise から値を解決する場合、この値に基づいて何らかのビジネス ロジック処理を実行する必要があります。

このビジネス ロジックが非常に長い場合は、次に長いビジネス ロジック コードを記述する必要があります。これにより、コードが非常に冗長に見えます。

では、promise で解決の結果を直接返す方法はありますか?

答えは待ってください。

promise の前に await がある場合、呼び出しコードは、promise が解決または拒否されるまで停止します。

await は async 関数内に配置する必要があることに注意してください。async と await の例を見てみましょう。

定数 logAsync = () => {
 新しいPromiseを返します(resolve => {
 setTimeout(() => 解決('小馬歌'), 5000)
 })
}

上記では、Promise を返す logAsync 関数を定義しました。Promise は setTimeout を使用して解決するため、非同期であるとみなすことができます。

await を使用してresolveの値を取得するには、それをasync関数に配置する必要があります。

定数doSomething = async() => {
 const 解決値 = logAsync() を待機します。
 コンソールにログ出力します。
}

非同期実行順序

Await は実際には promise の解決結果を待ちます。上記の例を組み合わせてみましょう。

定数 logAsync = () => {
 新しいPromiseを返します(resolve => {
  setTimeout(() => 解決('小馬歌'), 1000)
 })
}

定数doSomething = async() => {
 const 解決値 = logAsync() を待機します。
 コンソールにログ出力します。
}

console.log('前')
何かを実行します();
console.log('後')

上記の例の出力は次のようになります。

前に

リトル・マ

ご覧のとおり、aysnc は非同期で実行され、そのシーケンスは現在のサイクルの後にあります。

非同期の機能

後続の関数が明示的に Promise を返さない場合でも、Async は後続のすべての関数を Promise に変換します。

定数asyncReturn = async() => {
 '非同期戻り' を返す
}

asyncReturn().then(console.log)

then の後に続くことができるのは Promise のみであるため、async は通常の関数を Promise にカプセル化していることがわかります。

定数asyncReturn = async() => {
 Promise.resolve('async return') を返します。
}

asyncReturn().then(console.log)

要約する

Promise は、コールバック内のコールバックを then のチェーン呼び出しに書き換えることで、コールバック地獄を回避します。

しかし、チェーン呼び出しは読み取りやデバッグには不便です。そこで async と await が登場しました。

async と await は、チェーン呼び出しをプログラムの順次実行に似た構文に変更し、理解とデバッグを容易にします。

比較してみましょう。まず Promise の使用法を見てみましょう。

定数 getUserInfo = () => {
 return fetch('/users.json') // ユーザーリストを取得します。then(response => response.json()) // JSON を解析します。
 .then(users => users[0]) // 最初のユーザーを選択します。then(user => fetch(`/users/${user.name}`)) // ユーザーデータを取得します。then(userResponse => userResponse.json()) // JSON を解析します。
}

ユーザー情報を取得する()

これを async と await で書き直します。

const getUserInfo = 非同期() => {
 const response = await fetch('/users.json') // ユーザーリストを取得 const users = await response.json() // JSONを解析
 const user = users[0] // 最初のユーザーを選択 const userResponse = await fetch(`/users/${user.name}`) // ユーザーデータを取得 const userData = await userResponse.json() // JSONを解析
 ユーザーデータを返す
}

ユーザー情報を取得する()

ビジネスロジックがより明確になっていることがわかります。同時に、多くの中間値が得られるため、デバッグが容易になります。

これで、Node.js での非同期プログラミングの詳細な理解に関するこの記事は終了です。より関連性の高い Node.js 非同期プログラミング コンテンツについては、123WORDPRESS.COM で以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • シングルスレッドJavaScriptにおける非同期処理実装の詳細な説明
  • JSシングルスレッド非同期IOコールバックの特性を分析する
  • Javascript 非同期プログラミング: Promise を本当に理解していますか?
  • JavaScript 非同期プログラミングにおける Promise の初期の使用法の詳細な説明
  • JS 非同期実行の原則とコールバックの詳細
  • 最新の JavaScript で非同期タスクを書く方法
  • Node.js の非同期ジェネレータと非同期反復の詳細な説明
  • Node.js における非同期プログラミングの知識ポイントの詳細な説明
  • JS の 3 つの主要な問題、非同期性とシングルスレッドについて簡単に説明します。

<<:  MySQL 5.7 zip版(zip版)のインストールと設定手順の詳細

>>:  Linux でも利用できる人気の Windows アプリ 10 選

推薦する

WeChatアプレットは左にスワイプしてリスト項目を削除する効果を実現

この記事では、WeChatミニプログラムの具体的なコードを共有し、左にスワイプしてリスト項目を削除す...

MySQL Server 8.0.13.0 インストールチュートリアル(画像とテキスト付き)

MySQL 6.1.3 をベースにした 8.0.13 をインストールします。 MySQL 8.0....

Centos7 での NFS サービス構築の紹介

目次1. サーバー2. クライアント3. テストサービス1. サーバー1. YUMソースを使用してN...

XHTML コードで Marquee タグを使用する方法

フォーラムで、ネットユーザーの jeanjean20 が、Marquee を標準に適合させる方法につ...

Vueコンポーネント間のデータ共有の詳細な説明

目次1. プロジェクト開発において、コンポーネント間の最も一般的な関係は次の 2 つのタイプに分けら...

よく使われる HTML タグとその特徴の完全なリスト

まず、HTML タグのいくつかの特性を知っておく必要があります。 1. 「<keyword&g...

MySQLデータベースに他のIPアドレスからアクセスできない問題の解決策

序文先ほどのプロジェクトを参考にすると、環境は整いました。プロジェクトの準備と検証の段階で、問題が発...

JavaScript が Jingdong の虫眼鏡効果を模倣

この記事では、Jingdongの虫眼鏡効果を実現するためのJavaScriptの具体的なコードを紹介...

MySQLでよく使われるSQLとコマンドの入力からデータベースの削除、そして終了まで

目次開始と停止データベース関連の操作データベーステーブル関連の操作制約関連デフォルトの制約高度なデー...

docker での psql データベースのバックアップとリカバリの詳細な説明

1. DockerでのPostgresデータベースのバックアップ注文: docker exec it...

Vue のミックスインの使用方法の詳細な説明

目次序文1. Mixin とは何ですか? 2. Mixin はいつ使用すればよいですか? 3. Mi...

Reactでカスタムフックを作成する方法を教えます

1. カスタムフックとは何かロジックの再利用簡単に言えば、カスタム フックを使用すると、特定のコンポ...

CentOS 7 でゲートウェイを変更して IP を設定する方法の例

Centos7 バージョンをインストールするときに、外部ネットワークへの接続を選択すると、外部ネット...

XHTMLタグは適切に使用する必要があります

<br />123WORDPRESS.COM の以前のチュートリアルでは、Web ページ...