ホームページ  >  記事  >  ウェブフロントエンド  >  async/await の詳細

async/await の詳細

hzc
hzc転載
2020-06-15 09:53:162676ブラウズ

はじめに

面接中に、async/await は候補者の知識を確認する良い方法です。もちろん、この知識ポイントをどのような角度から説明するかは考えていません。インタビュアーに質問された場合は、自己実行ジェネレーターの構文糖について答えることができます。しかし、私はそれに少し気づいたでしょうか、それとも彼の認識を見たでしょうか?

babel の実装方法

注: ジェネレーターについて知らない場合は、まずジェネレーターを見て、ついでにイテレーターを見てみるのも良いでしょう。

例コード:

async function t() {
    const x = await getResult();
  	const y = await getResult2();
  	return x + y;
}

babel 変換コード

"use strict";

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
    try {
        var info = gen[key](arg);
        var value = info.value;
    } catch (error) {
        reject(error);
        return;
    }
    if (info.done) {
        resolve(value);
    } else {
        Promise.resolve(value).then(_next, _throw);
    }
}

function _asyncToGenerator(fn) {
    return function () {
        var self = this, args = arguments;
        return new Promise(function (resolve, reject) {
            var gen = fn.apply(self, args);
            function _next(value) {
                asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
            }
            function _throw(err) {
                asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
            }
            _next(undefined);
        });
    };
}

function t() {
  return _t.apply(this, arguments);
}

function _t() {
  _t = _asyncToGenerator(function* () {
    const x = yield getResult();
    const y = yield getResult2();
    return x + y;
  });
  return _t.apply(this, arguments);
}

コードからわかるように、babelgenerator を変換します。 async の場合、_asyncToGeneratorasyncGeneratorStep の 2 つのステップが使用されます。

_asyncToGenerator何をしたのか

1. _asyncToGenerator を呼び出すと、promise が返されましたが、これはたまたま と一致していました。 async 関数は then 機能に接続できます。

2. 成功したメソッド _next を定義し、失敗したメソッド _throw を定義します。 2 つの関数では、asyncGeneratorStep が呼び出されます。 asyncGeneratorStep を読むと、これが実際には再帰であることがわかります。

3. _nextを実行します。それが上記の自己実行ジェネレーターです。

asyncGeneratorStep実行内容

1. Try-catch を実行して、generator の実行中にエラーをキャプチャします。エラーが報告された場合、async 関数は直接 reject ステータスに入ります。

2. infodone 値が true かどうかを確認します。true の場合、イテレータが実行されたことを意味します。値を 解決できます。 ###外出。それ以外の場合は、引き続き _next を呼び出して値を次の値に渡します。

这里我唯一没有看明白的是`_throw`,这个看代码像是执行不到的。promise.resolve状态值应该是fulfilled。看懂的
可以在评论中和我说一下,感谢。

async/await の利点

新しい構文糖衣が登場するたびに、前世代のソリューションの欠点を補わなければなりません。

例:

promise の出現は、

コールバック地獄 を回避するためです。これを回避する方法は、呼び出しをチェーンすることです。

async/await は何を解決しますか?


promise を async/await に置き換える必要性

非同期を処理する同期方法

async/await は同期スタイルに近いですが、promise はasync/awaitと比べるとコードが大きくなり、async/awaitと同期関数の違いはあまりありませんが、promiseの書き方にはまだギャップがあります。

Promise コードと async/await コードの比較

Promise バージョン

function getData() {
    getRes().then((res) => {
        console.log(res);
    })
}

async/await バージョン

const getData = async function() {
    const res = await getRes();
    console.log(res);
}

中間値

Promise を使用する場合、複数の Promise がシリアル化されると、後続の Promise が前の Promise の値を取得することが非常に困難であることがわかります。そして、async はこの問題を正確に解決します。

中間値を取得するための約束の例

const morePromise = () => {
	return promiseFun1().then((value1) => {
		return promiseFun2(value1).then((value2) => {
			return promiseFun3(value1, value2).then((res) => {
				console.log(res);
			})
		}) 
	})
}

上記はネストされたバージョンですが、さまざまなニーズに応じてネストできない場合があります。

const morePromise = () => {
	return promiseFun1().then((value1) => {
		return promiseAll([value1, promiseFun2(value1)])
	}).then(([value1, value2]) => {
		return promiseFun3(value1, value2).then((res) => {
			console.log(res);
		})
	})
}

ネストレベルは減りましたが、それでも満足のいくものではありません。

async/await 最適化の使用例

const morePromise = async function() {
	const value1 = await promiseFun1();
	const value2 = await promiseFun2(value1);
	const res = await promiseFun3(value1, valuw2);
	return res;
}

シリアル非同期プロセスには中間値が含まれる必要があるため、async/await の利点は明らかです。

条件付きステートメントの状況

たとえば、現在要件があるとします。データをリクエストした後、さらにデータをリクエストする必要があるかどうかを判断できます。 Promise を使用して実装した場合でも、ネストされたレベルが存在します。

const a = () => {
    return getResult().then((data) => {
        if(data.hasMore) {
            return getMoreRes(data).then((dataMore) => {
                return dataMore;
            })
        } else {
            return data;
        }
    })
}

ただし、async を使用してこの例を最適化すると、コードがより美しくなります。

async/await 最適化の例

const a = async() => {
    const data = await getResult();
    if(data.hasMore) {
        const dataMore = await getMoreRes(data);
        return dataMore;
    } else {
        return data;
    }
}

async/await の欠点

上で async/await の利点のいくつかについて説明しましたが、async/await は万能ではありません。 . .上記はすべてシリアル非同期シナリオに関するものです。並列非同期シナリオに移行する場合。

並列非同期シナリオ

const a = async function() {
    const res = await Promise.all[getRes1(), getRes2()];
    return res;
}

async/await エラー処理

エラー キャプチャでの async/await を実装するには、promise.all を使用する必要があります。主な側面はトライキャッチです。

try-catch

const a = async () => {
    try{
        const res = await Promise.reject(1);
    } catch(err) {
        console.log(err);
    }
}

promise のキャッチ

これを行うためにパブリック関数を抽出できます。各 Promise の後に catch 処理が続くため、コードは非常に長くなります。

const a = async function() {
    const res = await Promise.reject(1).catch((err) => {
        console.log(err);
    })
}
// 公共函数

function errWrap(promise) {
    return promise().then((data) => {
        return [null, data];
    }).catch((err) => {
        return [err, null];
    })
}

推奨チュートリアル: 「

JS チュートリアル

以上がasync/await の詳細の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。