今回は、async/awaitの無駄なパフォーマンスの問題に対処する方法と、async/awaitの無駄なパフォーマンスの問題に対処する際の注意点について説明します。以下は実際的なケースです。一見。
はじめに
async/awaitとは
async/awaitは、coモジュールとgenerator関数の糖衣構文であると言えます。より明確なセマンティクスで js 非同期コードを解決します。
co モジュールに精通している学生は、co モジュールがマスター TJ によって作成されたモジュールであり、ジェネレーター関数を使用して非同期プロセスを解決するモジュールであることを知っているはずです。ジェネレーター関数の実行者と見なすことができます。 Async/await は co モジュールへのアップグレードであり、ジェネレーター関数エグゼキューターが組み込まれており、co モジュールに依存しなくなりました。同時に、async は Promise を返します。
上記の観点から、co モジュールにしろ async/await にしろ、Promise についてよく知らない学生は、まず Promise について詳しく学ぶことができます。
async/await を書くのは素晴らしいですが、次の問題に注意する必要があります。
async/await はコールバック地獄から解放しますが、async/await 地獄の問題が生じます。
async/await 地獄とは何ですか
JavaScript で非同期プログラミングを行うとき、多くの場合、ステートメントは前のステートメントに依存する必要がありません。パフォーマンスの問題を引き起こす可能性があります。
地獄の async/await の例
ピザと飲み物を買うプログラムを書いてみましょう:
(async () => { const pizzaData = await getPizzaData() // async call const drinkData = await getDrinkData() // async call const chosenPizza = choosePizza() // sync call const chosenDrink = chooseDrink() // sync call await addPizzaToCart(chosenPizza) // async call await addDrinkToCart(chosenDrink) // async call orderItems() // async call })()
このコードは問題なく実行されます。ただし、不必要な待機が追加されるため、これは良い実装とは言えません。
説明
コードを非同期 IIFE にカプセル化し、次の順序で実行しました:
ピザのリストを取得する
ドリンクのリストを取得する
リストからピザを選択する
からドリンクを選択するリスト
選択したピザをショッピングカートに追加します
選択したドリンクをショッピングカートに追加します
ショッピングカート内の商品を注文します
質問
ここに質問があります リストからピザを選択するアクションはなぜ行われますかドリンクリストを入手するまで待つ必要がありますか?これら 2 つは無関係な操作です。関連する操作には 2 つのグループがあります:
ピザ リストの取得 - 》ピザの選択 - ショッピング カートに追加するピザの選択
飲み物リストの取得 - 》飲み物の選択 -> ショッピング カートに追加する飲み物の選択
これら 2 つのセット操作は同時に実行する必要があります。
もっと悪い例を見てみましょう
この Javascript コード スニペットは、ショッピング カート内の商品を取得し、注文リクエストを作成します。
async function orderItems() { const items = await getCartItems() // async call const noOfItems = items.length for(var i = 0; i < noOfItems; i++) { await sendRequest(items[i]) // async call } }
この場合、for ループは次の反復に進む前に、sendRequest() 関数が完了するのを待つ必要があります。しかし、待つ必要はありません。すべてのリクエストをできるだけ早く送信したいと考えています。その後、すべてのリクエストが完了するまで待ちます。
これで、async/await 地獄についてよりよく理解できたはずです。今度は別の質問を考えてみましょう
await キーワードを忘れたらどうなるでしょうか?
非同期関数を呼び出すときに await を使用するのを忘れた場合、関数の実行を待つ必要がないことを意味します。 async 関数は、後で使用できる Promise を直接返します。
(async () => { const value = doSomeAsyncTask() console.log(value) // an unresolved promise })()
または、プログラムが明確ではないため、関数の実行が完了するまで待機したい場合は、直接 exit を実行してもこの非同期タスクは完了しません。したがって、 await キーワードを使用する必要があります。
promise には興味深い特性があり、コードの特定の行で Promise を取得し、それが別の場所で解決されるのを待つことができます。これが async/await 地獄を解決する鍵です。
(async () => { const promise = doSomeAsyncTask() const value = await promise console.log(value) // the actual value })()
ご覧のとおり、doSomeAsyncTask は Promise を直接返します。同時に、非同期関数 doSomeAsyncTask の実行が開始されています。doSomeAsyncTask の戻り値を取得するには、async/ を回避する方法を待機する必要があります。地獄を待ってください
首先我们需要知道哪些命名是有前后依赖关系的。
然后将有依赖关系的系列操作进行分组合并成一个异步操作。
同时执行这些异步函数。
我们来重写这写例子:
async function selectPizza() { const pizzaData = await getPizzaData() // async call const chosenPizza = choosePizza() // sync call await addPizzaToCart(chosenPizza) // async call } async function selectDrink() { const drinkData = await getDrinkData() // async call const chosenDrink = chooseDrink() // sync call await addDrinkToCart(chosenDrink) // async call } (async () => { const pizzaPromise = selectPizza() const drinkPromise = selectDrink() await pizzaPromise await drinkPromise orderItems() // async call })() // Although I prefer it this way (async () => { Promise.all([selectPizza(), selectDrink()].then(orderItems) // async call })()
我们将语句分成两个函数。在函数内部,每个语句都依赖于前一个语句的执行。然后我们同时执行这两个函数 selectPizza()和selectDrink() 。
在第二个例子中我们需要处理未知数量的 Promise。处理这个问题非常简单,我们只需要创建一个数组将所有 Promise 存入其中,使用 Promise.all() 方法并行执行:
async function orderItems() { const items = await getCartItems() // async call const noOfItems = items.length const promises = [] for(var i = 0; i < noOfItems; i++) { const orderPromise = sendRequest(items[i]) // async call promises.push(orderPromise) // sync call } await Promise.all(promises) // async call }
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
React怎样在react-router路由实现登陆验证控制
以上がasync/await の無駄なパフォーマンスの問題に対処する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。