Node.js における非同期プログラミングの知識ポイントの詳細な説明

Node.js における非同期プログラミングの知識ポイントの詳細な説明

導入

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 つの特性があります。

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

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

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

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

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

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

約束の利点

  1. Promise は、ネストされたコールバック関数を回避して、非同期操作を同期操作の形式で表現します。
  2. 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 を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • JS組み込みオブジェクトとMathオブジェクトの詳細な説明
  • VsCodeとNode.jsの知識ポイントの詳細な説明
  • Node.jsによるMySQLデータベースへの接続と基礎知識のポイントを詳しく説明
  • 写真の滝効果の詳しい説明(js、jqueryの実装と知識ポイントのまとめ)
  • JavaScript 知識ポイントのまとめ (XVI) Javascript クロージャコードの詳細な説明
  • JavaScript の知識ポイントのまとめ (XI) js の Object クラスの詳細な説明
  • JavaScriptの知識ポイントまとめ(IV)論理OR演算子の詳しい説明
  • JavaScriptの知識ポイントの詳しい説明

<<:  Angularが予期しない例外エラーを処理する方法の詳細な説明

>>:  js 加算、減算、乗算、除算の正確な計算方法のサンプルコード

推薦する

基本構造、ドキュメント タイプ、ヘッダー、本文などの一般的な HTML 要素の概要。

1. 基本構造:コードをコピーコードは次のとおりです。 <!DOCTYPE html PUBL...

vsftpd ユーザーが ssh 経由でログインすることを禁止する方法

序文vsftp は使いやすく安全な FTP サーバー ソフトウェアです。システムユーザーまたは仮想ユ...

Win10 インストール Linux システム チュートリアル ダイアグラム

Windows システムに仮想マシンをインストールするには、 VMware Workstationソ...

SQLベースのクエリステートメント

目次1. 基本的なSELECT文1. 指定されたフィールドをクエリする3. エイリアスを設定する4....

W3C チュートリアル (2): W3C プログラム

W3C 標準化プロセスは 7 つの異なるステップに分かれています。 W3C 標準化プロセスは 7 つ...

テキストエリアタグはサイズ変更できず、マウスでドラッグすることもできません

テキストエリアタグのサイズは不変ですコードをコピーコードは次のとおりです。 <textarea...

Vue3とTypeScriptを組み合わせたプロジェクト開発の実践の概要

目次概要1. コンポジションAPI 1. ref と reactive の違いは何ですか? 2. 周...

JS での Reduce Fold Unfold の使用法の詳細な説明

目次折りたたむ(減らす) for...of の使用whileループの使用折り畳み実装に近い展開する配...

要素のフォーム要素の使用の概要

フォーム要素はたくさんあります。簡単にまとめると、次のようになります。私のやり方では、主にテキスト ...

vue+rem カスタムカルーセル効果

vue+remを使用したカスタムカルーセルチャートの実装は参考までに。具体的な内容は以下のとおりです...

Vue+WebSocket ページでの長時間接続のリアルタイム更新

最近、Vue プロジェクトではデータをリアルタイムで更新する必要があります。折れ線グラフは 1 秒ご...

Centos7にTenda U12ワイヤレスネットワークカードドライバーをインストールする際の問題を解決する

解決プロセス:方法1: CentOS7.3 のデフォルトのカーネル バージョンは低く、3.10.0-...

CSS フロートプロパティ図 フロートプロパティの詳細

CSS の float プロパティを正しく使用することは、カバーすべき内容が多く、ブラウザの互換性の...

JDBC が MySQL に接続して中国語を処理するときに文字化けする問題の解決方法の詳細説明

JDBC が MySQL に接続して中国語を処理するときに文字化けする問題の解決方法の詳細説明最近、...

Ubuntuがネットワークに接続できない場合の解決策

仮想マシン内の Ubuntu がネットワークに接続できない場合の効果的な解決策: 1. Ubuntu...