ホームページ ウェブフロントエンド jsチュートリアル js async関数の書き方手順を詳しく解説

js async関数の書き方手順を詳しく解説

May 22, 2018 am 09:49 AM
async javascript 詳しい説明

今回は、js async 関数を記述する手順について詳しく説明します。js async 関数を記述する際の 注意点 は何ですか?実際のケースを見てみましょう。

2018 年が 5 月に到来し、ノードの 4.x バージョンもメンテナンスを停止しました。現在、koa2.x に移行し、以前のジェネレーターをすべて非同期に置き換えています。ただし、置換プロセス中に、非同期の乱用による時間の無駄が判明したため、非同期コードを最適化し、非同期イベント ストリームを最大限に活用して非同期の乱用を排除する方法について説明します

まず、すべて、Promise を理解する必要があります

Promise は async/await を使用するための基礎であるため、最初に Promise が何をするのかを理解する必要があります

Promise はコールバック地獄を解決するのに役立ち、非同期プロセスをより明確にすることができます。

Error-first-callback を Promise に変換する簡単な例:

const fs = require('fs')
function readFile (fileName) {
 return new Promise((resolve, reject) => {
  fs.readFile(fileName, (err, data) => {
   if (err) reject(err)
   resolve(data)
  })
 })
}
readFile('test.log').then(data => {
 console.log('get data')
}, err => {
 console.error(err)
})
ログイン後にコピー
Promise インスタンスを返す関数を呼び出し、インスタンス化プロセス中にファイルを読み取ります。ファイル読み取りのコールバックがトリガーされると、 then を使用します。 Promise ステータス、解決済みまたは拒否されたステータスの変化を監視します。最初のコールバックは解決処理用であり、2 番目のコールバックは拒否処理用です。

async と Promise の関係

async 関数は、Promise インスタンスを返す短縮関数と同等であり、その効果は次のとおりです:

function getNumber () {
 return new Promise((resolve, reject) => {
  resolve(1)
 })
}
// =>
async function getNumber () {
 return 1
}
ログイン後にコピー
この 2 つは使用上まったく同じであり、後で使用できます。 getNumber 関数を呼び出して戻り値を監視します。 そして、async に対応する await 構文の使用方法:

getNumber().then(data => {
 // got data
})
// =>
let data = await getNumber()
ログイン後にコピー
await を実行すると、

expression の背後にある Promise 実行結果が取得されます。これは、コールバック結果を取得するために then を呼び出すのと同等です。追伸: async/await のサポートがそれほど高くなかったときは、誰もが同様の効果を達成するために、co に似たいくつかのライブラリとジェネレーター/yield を組み合わせて使用​​することを選択していました

async 関数のコードの実行は同期であり、結果の戻りは非同期です

async 関数常に Promise のインスタンスを返します。これは非常に重要です。そのため、async 関数を呼び出すと、内部のコードが新しい Promise にあることがわかり、同期的に実行され、最後の return 操作は、resolve を呼び出した場合と同じになります。 Promise:

async function getNumber () {
 console.log('call getNumber()')
 return 1
}
getNumber().then(_ => console.log('resolved'))
console.log('done')
// 输出顺序:
// call getNumber()
// done
// resolved
ログイン後にコピー

Promise内のPromiseはダイジェストされます

つまり、次のコードがある場合:

function getNumber () {
 return new Promise(resolve => {
  resolve(Promise.resolve(1))
 })
}
getNumber().then(data => console.log(data)) // 1
ログイン後にコピー
上記の内容に従えば、データは取得されます。別の Promise インスタンスであるsolveに渡される値。

しかし実際には、戻り値を直接取得します。 1. つまり、Promise が Promise で返された場合、プログラムは実際にこの Promise の実行を支援し、内部 Promise の状態が変化したときなどにコールバックをトリガーします。 。
興味深い点:

function getNumber () {
 return new Promise(resolve => {
  resolve(Promise.reject(new Error('Test')))
 })
}
getNumber().catch(err => console.error(err)) // Error: Test
ログイン後にコピー
解決で拒否を渡す場合、catch を直接使用して外部からそれを監視できます。

このメソッドは、非同期関数で例外をスローするためによく使用されます
非同期関数で例外をスローする方法:

await キーワードを忘れないように注意してください await キーワードを追加するのを忘れた場合は、コードレベル Noエラーは報告されますが、受け取る戻り値は Promise です

let number = getNumber()
console.log(number) // Promise
ログイン後にコピー

ので、それを使用するときは、await キーワードを必ず覚えておいてください

let number = await getNumber()
console.log(number) // 1
ログイン後にコピー
ログイン後にコピー

すべての場所に await を追加する必要があるわけではありません

コードの実行中に、現時点では、すべての非同期操作で await を追加する必要があるわけではありません。 たとえば、ファイルに対する次の操作:

fs のすべての API が私たちによって Promise バージョンに変換されていると仮定します

let number = await getNumber()
console.log(number) // 1
ログイン後にコピー
ログイン後にコピー

await を通じてファイルを開き、ファイルを 2 回書き込みます。

ただし、2 つのファイル書き込み操作の前に await キーワードを追加していないことに注意してください。

これは冗長であるため、このファイルにテキスト行を書き込みたいことを API に通知するだけで済みます。順序は当然 fs によって制御されます。

その後、最後に await を使用してファイルを閉じます。
上記の書き込み処理を実行しても、close コールバックはトリガーされないためです。
つまり、コールバックのトリガーは、上記の 2 つの書き込みステップが完了したことを意味します。

合并多个不相干的async函数调用

如果我们现在要获取一个用户的头像和用户的详细信息(而这是两个接口 虽说一般情况下不太会出现)

async function getUser () {
 let avatar = await getAvatar()
 let userInfo = await getUserInfo()
 return {
  avatar,
  userInfo
 }
}
ログイン後にコピー

这样的代码就造成了一个问题,我们获取用户信息的接口并不依赖于头像接口的返回值。
 但是这样的代码却会在获取到头像以后才会去发送获取用户信息的请求。
 所以我们对这种代码可以这样处理:

async function getUser () {
 let [avatar, userInfo] = await Promise.all([getAvatar(), getUserInfo()])
 return {
  avatar,
  userInfo
 }
}
ログイン後にコピー

这样的修改就会让getAvatar与getUserInfo内部的代码同时执行,同时发送两个请求,在外层通过包一层Promise.all来确保两者都返回结果。

让相互没有依赖关系的异步函数同时执行

一些循环中的注意事项

forEach

当我们调用这样的代码时:

async function getUsersInfo () {
 [1, 2, 3].forEach(async uid => {
  console.log(await getUserInfo(uid))
 })
}
function getuserInfo (uid) {
 return new Promise(resolve => {
  setTimeout(_ => resolve(uid), 1000)
 })
}
await getUsersInfo()
ログイン後にコピー

这样的执行好像并没有什么问题,我们也会得到1、2、3三条log的输出,但是当我们在await getUsersInfo()下边再添加一条console.log('done')的话,就会发现:

 我们会先得到done,然后才是三条uid的log,也就是说,getUsersInfo返回结果时,其实内部Promise并没有执行完。
 这是因为forEach并不会关心回调函数的返回值是什么,它只是运行回调。

不要在普通的for、while循环中使用await

使用普通的for、while循环会导致程序变为串行:

for (let uid of [1, 2, 3]) {
 let result = await getUserInfo(uid)
}
ログイン後にコピー

这样的代码运行,会在拿到uid: 1的数据后才会去请求uid: 2的数据

--------------------------------------------------------------------------------

关于这两种问题的解决方案:

目前最优的就是将其替换为map结合着Promise.all来实现:

await Promise.all([1, 2, 3].map(async uid => await getUserInfo(uid)))
ログイン後にコピー
ログイン後にコピー

这样的代码实现会同时实例化三个Promise,并请求getUserInfo

P.S. 草案中有一个await*,可以省去Promise.all

await Promise.all([1, 2, 3].map(async uid => await getUserInfo(uid)))
ログイン後にコピー
ログイン後にコピー

P.S. 为什么在使用Generator+co时没有这个问题

在使用koa1.x的时候,我们直接写yield [].map是不会出现上述所说的串行问题的看过co源码的小伙伴应该都明白,里边有这么两个函数(删除了其余不相关的代码):

function toPromise(obj) {
 if (Array.isArray(obj)) return arrayToPromise.call(this, obj);
 return obj;
}
function arrayToPromise(obj) {
 return Promise.all(obj.map(toPromise, this));
}
ログイン後にコピー

co是帮助我们添加了Promise.all的处理的(膜拜TJ大佬)。

总结

总结一下关于async函数编写的几个小提示:

1.使用return Promise.reject()在async函数中抛出异常
2.让相互之间没有依赖关系的异步函数同时执行
3.不要在循环的回调中/for、while循环中使用await,用map来代替它

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

js中async函数使用方法详解

node搭建服务器,写接口,调接口,跨域方法详解

以上がjs async関数の書き方手順を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

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

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

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

Win11での管理者権限の取得について詳しく解説 Win11での管理者権限の取得について詳しく解説 Mar 08, 2024 pm 03:06 PM

Windows オペレーティング システムは世界で最も人気のあるオペレーティング システムの 1 つであり、その新バージョン Win11 が大きな注目を集めています。 Win11 システムでは、管理者権限の取得は重要な操作であり、管理者権限を取得すると、ユーザーはシステム上でより多くの操作や設定を実行できるようになります。この記事では、Win11システムで管理者権限を取得する方法と、権限を効果的に管理する方法を詳しく紹介します。 Win11 システムでは、管理者権限はローカル管理者とドメイン管理者の 2 種類に分かれています。ローカル管理者はローカル コンピュータに対する完全な管理権限を持っています

Oracle SQLの除算演算の詳細説明 Oracle SQLの除算演算の詳細説明 Mar 10, 2024 am 09:51 AM

OracleSQL の除算演算の詳細な説明 OracleSQL では、除算演算は一般的かつ重要な数学演算であり、2 つの数値を除算した結果を計算するために使用されます。除算はデータベース問合せでよく使用されるため、OracleSQL での除算演算とその使用法を理解することは、データベース開発者にとって重要なスキルの 1 つです。この記事では、OracleSQL の除算演算に関する関連知識を詳細に説明し、読者の参考となる具体的なコード例を示します。 1. OracleSQL での除算演算

PHPモジュロ演算子の役割と使い方を詳しく解説 PHPモジュロ演算子の役割と使い方を詳しく解説 Mar 19, 2024 pm 04:33 PM

PHP のモジュロ演算子 (%) は、2 つの数値を除算した余りを取得するために使用されます。この記事では、モジュロ演算子の役割と使用法について詳しく説明し、読者の理解を深めるために具体的なコード例を示します。 1. モジュロ演算子の役割 数学では、整数を別の整数で割ると、商と余りが得られます。たとえば、10 を 3 で割ると、商は 3 になり、余りは 1 になります。モジュロ演算子は、この剰余を取得するために使用されます。 2. モジュロ演算子の使用法 PHP では、% 記号を使用してモジュロを表します。

Linuxシステムコールsystem()関数の詳細説明 Linuxシステムコールsystem()関数の詳細説明 Feb 22, 2024 pm 08:21 PM

Linux システム コール system() 関数の詳細説明 システム コールは、Linux オペレーティング システムの非常に重要な部分であり、システム カーネルと対話する方法を提供します。その中でも、system()関数はよく使われるシステムコール関数の一つです。この記事では、system() 関数の使用法を詳しく紹介し、対応するコード例を示します。システム コールの基本概念 システム コールは、ユーザー プログラムがオペレーティング システム カーネルと対話する方法です。ユーザープログラムはシステムコール関数を呼び出してオペレーティングシステムを要求します。

簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 Jan 05, 2024 pm 06:08 PM

JavaScript チュートリアル: HTTP ステータス コードを取得する方法、特定のコード例が必要です 序文: Web 開発では、サーバーとのデータ対話が頻繁に発生します。サーバーと通信するとき、多くの場合、返された HTTP ステータス コードを取得して操作が成功したかどうかを判断し、さまざまなステータス コードに基づいて対応する処理を実行する必要があります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法を説明し、いくつかの実用的なコード例を示します。 XMLHttpRequestの使用

C言語学習ルートを詳細に分析 C言語学習ルートを詳細に分析 Feb 18, 2024 am 10:38 AM

ソフトウェア開発の分野で広く使用されているプログラミング言語として、C 言語は多くの初心者プログラマーにとって最初の選択肢です。 C言語を学ぶと、プログラミングの基礎知識を定着させるだけでなく、問題解決能力や思考力も向上します。この記事では、初心者が学習プロセスをより適切に計画できるようにするための C 言語学習ロードマップを詳しく紹介します。 1. 基本的な文法を学ぶ C 言語の学習を始める前に、まず C 言語の基本的な文法規則を理解する必要があります。これには、変数とデータ型、演算子、制御ステートメント (if ステートメント、

Linuxのcurlコマンドの詳しい説明 Linuxのcurlコマンドの詳しい説明 Feb 21, 2024 pm 10:33 PM

Linuxのcurlコマンドの詳細な説明 要約:curlは、サーバーとのデータ通信に使用される強力なコマンドラインツールです。この記事では、curl コマンドの基本的な使用法を紹介し、読者がコマンドをよりよく理解して適用できるように実際のコード例を示します。 1.カールとは何ですか? curl は、さまざまなネットワーク要求を送受信するために使用されるコマンド ライン ツールです。 HTTP、FTP、TELNETなどの複数のプロトコルをサポートし、ファイルアップロード、ファイルダウンロード、データ送信、プロキシなどの豊富な機能を提供します。

Promise.resolve() について詳しく見る Promise.resolve() について詳しく見る Feb 18, 2024 pm 07:13 PM

Promise.resolve() の詳細な説明には、特定のコード例が必要です。Promise は、非同期操作を処理するための JavaScript のメカニズムです。実際の開発では、順番に実行する必要があるいくつかの非同期タスクを処理する必要があることがよくあり、満たされた Promise オブジェクトを返すために Promise.resolve() メソッドが使用されます。 Promise.resolve() は Promise クラスの静的メソッドであり、

See all articles