この記事では、Node.js の Async 関数と Await 関数の関連知識を主に紹介します。Node.js で async 関数 (async/await) を使用してコールバックや Promise を簡素化する方法を学びます。参考値、困っている友達が参考になれば幸いです。
非同期言語構造は、C# の async/await、Kotlin のコルーチン、go の goroutine など、他の言語にすでに存在しています。Node.js 8 のリリースでは、待望の async 関数もデフォルトで実装されました。
Nodeの非同期関数とは何ですか?
関数が Async 関数として宣言されると、AsyncFunction オブジェクトが返されます。実行を一時停止できるという点で Generator に似ています。唯一の違いは、{ value: any、done: Boolean } オブジェクトの代わりに Promise を返すことです。ただし、これらは依然として非常に似ており、co パッケージを使用して同じ機能を取得できます。
非同期関数では、Promise が完了するまで待つことも、拒否された理由を取得することもできます。
Promise に独自のロジックを実装したい場合
function handler (req, res) { return request('https://user-handler-service') .catch((err) => { logger.error('Http error', err) error.logged = true throw err }) .then((response) => Mongo.findOne({ user: response.body.user })) .catch((err) => { !error.logged && logger.error('Mongo error', err) error.logged = true throw err }) .then((document) => executeLogic(req, res, document)) .catch((err) => { !error.logged && console.error(err) res.status(500).send() }) }
async/await を使用して、このコードを同期的に実行されるコードのように見せることができます
async function handler (req, res) { let response try { response = await request('https://user-handler-service') } catch (err) { logger.error('Http error', err) return res.status(500).send() } let document try { document = await Mongo.findOne({ user: response.body.user }) } catch (err) { logger.error('Mongo error', err) return res.status(500).send() } executeLogic(document, req, res) }
古い v8 バージョンでは、Promise の拒否がある場合、 ? が処理されると警告が表示されますが、拒否エラー リスニング関数を作成する必要はありません。ただし、この場合はアプリケーションを終了することをお勧めします。エラーを処理しないと、アプリケーションは不明な状態になるためです。
process.on('unhandledRejection', (err) => { console.error(err) process.exit(1) })
async 関数パターン
非同期操作を扱う場合、非同期操作を同期コードのように見せる例がたくさんあります。 Promise またはコールバックを使用して問題を解決する場合は、非常に複雑なパターンまたは外部ライブラリを使用する必要があります。
ループ内でデータの非同期取得を使用したり、if-else 条件を使用したりする必要がある場合は、非常に複雑な状況になります。
指数関数的ロールバック メカニズム
Promise を使用してロールバック ロジックを実装するのは非常に不格好です
function requestWithRetry (url, retryCount) { if (retryCount) { return new Promise((resolve, reject) => { const timeout = Math.pow(2, retryCount) setTimeout(() => { console.log('Waiting', timeout, 'ms') _requestWithRetry(url, retryCount) .then(resolve) .catch(reject) }, timeout) }) } else { return _requestWithRetry(url, 0) } } function _requestWithRetry (url, retryCount) { return request(url, retryCount) .catch((err) => { if (err.statusCode && err.statusCode >= 500) { console.log('Retrying', err.message, retryCount) return requestWithRetry(url, ++retryCount) } throw err }) } requestWithRetry('http://localhost:3000') .then((res) => { console.log(res) }) .catch(err => { console.error(err) })
コードは見るのが非常に面倒なので、そのようなコードは見たくないでしょう。この例を async/await を使用してやり直すと、より簡単になります
function wait (timeout) { return new Promise((resolve) => { setTimeout(() => { resolve() }, timeout) }) } async function requestWithRetry (url) { const MAX_RETRIES = 10 for (let i = 0; i <p>上記のコードはとても快適ですよね?</p><p>中間値</p><p>は、それぞれに依存する 3 つの async 関数がある場合、前の例ほど怖くありません他の場合は、いくつかの醜い解決策から選択する必要があります。 </p><p>functionA は Promise を返し、functionB はこの値を必要とし、functionA と functionB が完了した後の functionC は値を必要とします。 </p><p>オプション 1: 次にクリスマスツリー</p><pre class="brush:php;toolbar:false">function executeAsyncTask () { return functionA() .then((valueA) => { return functionB(valueA) .then((valueB) => { return functionC(valueA, valueB) }) }) }
この解決策を使用すると、3 番目の then で valueA と valueB を取得でき、その後、前の 2 つの then と同様に valueA と valueB の値を取得できます。ここではクリスマス ツリーを平らにすることはできません (破滅地獄)。平らにするとクロージャが失われ、valueA が functionC で使用できなくなります。
オプション 2: 上位レベルのスコープに移動
function executeAsyncTask () { let valueA return functionA() .then((v) => { valueA = v return functionB(valueA) }) .then((valueB) => { return functionC(valueA, valueB) }) }
このクリスマス ツリーでは、上位のスコープ リテイナー valueA を使用します。これは、valueA のスコープがすべてのスコープの外側にあるため、functionC は functionA によって完成された最初の A 値を取得できます。
これは .then チェーンをフラット化するための非常に「正しい」構文ですが、この方法では同じ値を保持するために 2 つの変数 valueA と v を使用する必要があります。
オプション 3: 追加の配列を使用する
function executeAsyncTask () { return functionA() .then(valueA => { return Promise.all([valueA, functionB(valueA)]) }) .then(([valueA, valueB]) => { return functionC(valueA, valueB) }) }
functionA の then で配列を使用して、valueA と Promise を一緒に返します。これにより、クリスマス ツリーを効果的に平坦化できます (コールバック地獄)。
オプション 4: ヘルパー関数を作成する
const converge = (...promises) => (...args) => { let [head, ...tail] = promises if (tail.length) { return head(...args) .then((value) => converge(...tail)(...args.concat([value]))) } else { return head(...args) } } functionA(2) .then((valueA) => converge(functionB, functionC)(valueA))
これは実行可能です。コンテキスト変数宣言をマスクするヘルパー関数を作成します。しかし、そのようなコードは、特にこれらの魔法に慣れていない人にとっては非常に読みにくいです。
async/await を使用すると、問題は魔法のように消えます
async function executeAsyncTask () { const valueA = await functionA() const valueB = await functionB(valueA) return function3(valueA, valueB) }
async/await を使用して複数の並列リクエストを処理します
上記と同様に、複数の非同期タスクを一度に実行し、それらを別の場所で使用したい場合async/await を使用すると簡単に判断できます。
async function executeParallelAsyncTasks () { const [ valueA, valueB, valueC ] = await Promise.all([ functionA(), functionB(), functionC() ]) doSomethingWith(valueA) doSomethingElseWith(valueB) doAnotherThingWith(valueC) }
配列反復メソッド
map、filter、reduce メソッドで非同期関数を使用できます。あまり直感的ではないように見えますが、コンソールで次のコードを試すことができます。
1.map
function asyncThing (value) { return new Promise((resolve, reject) => { setTimeout(() => resolve(value), 100) }) } async function main () { return [1,2,3,4].map(async (value) => { const v = await asyncThing(value) return v * 2 }) } main() .then(v => console.log(v)) .catch(err => console.error(err))
2.filter
function asyncThing (value) { return new Promise((resolve, reject) => { setTimeout(() => resolve(value), 100) }) } async function main () { return [1,2,3,4].filter(async (value) => { const v = await asyncThing(value) return v % 2 === 0 }) } main() .then(v => console.log(v)) .catch(err => console.error(err))
3.reduce
function asyncThing (value) { return new Promise((resolve, reject) => { setTimeout(() => resolve(value), 100) }) } async function main () { return [1,2,3,4].reduce(async (acc, value) => { return await acc + await asyncThing(value) }, Promise.resolve(0)) } main() .then(v => console.log(v)) .catch(err => console.error(err))
解決策:
[ Promise { <pending> }, Promise { <pending> }, Promise { <pending> }, Promise { <pending> } ] [ 1, 2, 3, 4 ] 10</pending></pending></pending></pending>
マップ反復データの場合、戻り値は [2, 4, 6, 8] であることがわかります。唯一の問題は、各値が AsyncFunction 関数によって Promise にラップされていることです
したがって、それらの値を取得したい場合は、配列を Promise.All() に渡して Promise のラップを解除する必要があります。
rreeeこれは簡単だと思いますか?
イテレーター内に長時間実行される同期ロジックと別の長時間実行される非同期タスクがある場合、async/await バージョンは引き続き役立ちます
このようにして、最初の値を取得できたら、何もしなくても計算を開始できます。計算を実行する前に、すべての Promise が完了するまで待機します。結果は Promise でラップされますが、結果を順番に実行した方が高速です。
フィルターに関する質問
你可能发觉了,即使上面filter函数里面返回了 [ false, true, false, true ] , await asyncThing(value) 会返回一个 promise 那么你肯定会得到一个原始的值。你可以在return之前等待所有异步完成,在进行过滤。
Reducing很简单,有一点需要注意的就是需要将初始值包裹在 Promise.resolve 中
重写基于callback的node应用成
Async 函数默认返回一个 Promise ,所以你可以使用 Promises 来重写任何基于 callback 的函数,然后 await 等待他们执行完毕。在node中也可以使用 util.promisify 函数将基于回调的函数转换为基于 Promise 的函数
重写基于Promise的应用程序
要转换很简单, .then 将Promise执行流串了起来。现在你可以直接使用`async/await。
function asyncTask () { return functionA() .then((valueA) => functionB(valueA)) .then((valueB) => functionC(valueB)) .then((valueC) => functionD(valueC)) .catch((err) => logger.error(err)) }
转换后
async function asyncTask () { try { const valueA = await functionA() const valueB = await functionB(valueA) const valueC = await functionC(valueB) return await functionD(valueC) } catch (err) { logger.error(err) } } Rewriting Nod
使用 Async/Await 将很大程度上的使应用程序具有高可读性,降低应用程序的处理复杂度(如:错误捕获),如果你也使用 node v8+的版本不妨尝试一下,或许会有新的收获。
相关推荐:
以上がNode.js での Async および Await 関数の分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

Javaandjavascriptaredistinctlanguages:javaisusedforenterpriseandmobileapps、whilejavascriptisforinteractivewebpages.1)javaiscompiled、staticatically、andrunsonjvm.2)javascriptisisterted、dynamsornoded.3)

JavaScriptコアデータ型は、ブラウザとnode.jsで一貫していますが、余分なタイプとは異なる方法で処理されます。 1)グローバルオブジェクトはブラウザのウィンドウであり、node.jsのグローバルです2)バイナリデータの処理に使用されるNode.jsの一意のバッファオブジェクト。 3)パフォーマンスと時間の処理にも違いがあり、環境に従ってコードを調整する必要があります。

javascriptusestwotypesofcomments:シングルライン(//)およびマルチライン(//)

PythonとJavaScriptの主な違いは、タイプシステムとアプリケーションシナリオです。 1。Pythonは、科学的コンピューティングとデータ分析に適した動的タイプを使用します。 2。JavaScriptは弱いタイプを採用し、フロントエンドとフルスタックの開発で広く使用されています。この2つは、非同期プログラミングとパフォーマンスの最適化に独自の利点があり、選択する際にプロジェクトの要件に従って決定する必要があります。

PythonまたはJavaScriptを選択するかどうかは、プロジェクトの種類によって異なります。1)データサイエンスおよび自動化タスクのPythonを選択します。 2)フロントエンドとフルスタック開発のためにJavaScriptを選択します。 Pythonは、データ処理と自動化における強力なライブラリに好まれていますが、JavaScriptはWebインタラクションとフルスタック開発の利点に不可欠です。

PythonとJavaScriptにはそれぞれ独自の利点があり、選択はプロジェクトのニーズと個人的な好みに依存します。 1. Pythonは、データサイエンスやバックエンド開発に適した簡潔な構文を備えた学習が簡単ですが、実行速度が遅くなっています。 2。JavaScriptはフロントエンド開発のいたるところにあり、強力な非同期プログラミング機能を備えています。 node.jsはフルスタックの開発に適していますが、構文は複雑でエラーが発生しやすい場合があります。

javascriptisnotbuiltoncorc;それは、解釈されていることを解釈しました。

JavaScriptは、フロントエンドおよびバックエンド開発に使用できます。フロントエンドは、DOM操作を介してユーザーエクスペリエンスを強化し、バックエンドはnode.jsを介してサーバータスクを処理することを処理します。 1.フロントエンドの例:Webページテキストのコンテンツを変更します。 2。バックエンドの例:node.jsサーバーを作成します。


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

WebStorm Mac版
便利なJavaScript開発ツール

SublimeText3 Linux 新バージョン
SublimeText3 Linux 最新バージョン

MinGW - Minimalist GNU for Windows
このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

SublimeText3 中国語版
中国語版、とても使いやすい

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)
