非同期/待機地獄の問題の処理

php中世界最好的语言
リリース: 2018-05-22 11:49:45
オリジナル
1934 人が閲覧しました

今回は、async/await 地獄問題への対処方法をお届けします。 async/await 地獄問題に対処する際の 注意点とは何ですか。実際のケースを見てみましょう。

はじめに

async/awaitとは

async/awaitは、coモジュールや

generatorfunctionの糖衣構文であると言えます。より明確なセマンティクスで 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/await 地狱

首先我们需要知道哪些命名是有前后依赖关系的。

然后将有依赖关系的系列操作进行分组合并成一个异步操作。

同时执行这些异步函数。

我们来重写这写例子:

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中文网其它相关文章!

推荐阅读:

vue按钮多次点击重复提交数据如何处理

vue-router3.0版本router.push无法刷新页面如何处理

以上が非同期/待機地獄の問題の処理の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート