91

この素晴らしい記事 «ジェネレーター» を読んでいたところ、ジェネレーター関数を処理するためのヘルパー関数であるこの関数が明確に強調されています。

function async(makeGenerator){
  return function () {
    var generator = makeGenerator.apply(this, arguments);

    function handle(result){
      // result => { done: [Boolean], value: [Object] }
      if (result.done) return Promise.resolve(result.value);

      return Promise.resolve(result.value).then(function (res){
        return handle(generator.next(res));
      }, function (err){
        return handle(generator.throw(err));
      });
    }

    try {
      return handle(generator.next());
    } catch (ex) {
      return Promise.reject(ex);
    }
  }
}

これは多かれ少なかれ、asyncキーワードがasync/で実装される方法であると仮定していawaitます。問題は、その場合、awaitキーワードとキーワードの違いは一体何なのかということyieldです。await常に何かを約束に変えますが、yieldそのような保証はしませんか? それが私の最善の推測です!

async/がジェネレーターとどのようawaitに似ているかyieldについては、彼が 'spawn' 関数ES7 async functionsについて説明しているこの記事で確認できます。

4

8 に答える 8

50

async/awaitとジェネレーターの間には非常に密接な関係があることがわかりました。asyncそして、 /awaitは常にジェネレーター上に構築されると信じています。Babel がasync/をトランスパイルする方法を見ると、次のようになりawaitます。

バベルはこれを取ります:

this.it('is a test', async function () {

    const foo = await 3;
    const bar = await new Promise(resolve => resolve('7'));
    const baz = bar * foo;
    console.log(baz);

});

そしてそれをこれに変えます

function _asyncToGenerator(fn) {
    return function () {
        var gen = fn.apply(this, arguments);
        return new Promise(function (resolve, reject) {
            function step(key, arg) {
                try {
                    var info = gen[key](arg);
                    var value = info.value;
                } catch (error) {
                    reject(error);
                    return;
                }
                if (info.done) {
                    resolve(value);
                } else {
                    return Promise.resolve(value).then(function (value) {
                        return step("next", value);
                    }, function (err) {
                        return step("throw", err);
                    });
                }
            }

            return step("next");
        });
    };
}


this.it('is a test', _asyncToGenerator(function* () {   // << now it's a generator

    const foo = yield 3;    //  <<< now it's yield, not await
    const bar = yield new Promise(resolve => resolve(7));
    const baz = bar * foo;
    console.log(baz);

}));

あなたが計算します。

これにより、キーワードがそのラッパー関数のように見えますasyncが、その場合awaitは に変換されるだけyieldで、後でネイティブになったときにもう少し画像が増える可能性があります。

詳細については、 https ://www.promisejs.org/generators/ を参照してください。

于 2016-03-27T08:10:35.403 に答える
32

awaitキーワードとキーワードの違いは何yieldですか?

awaitキーワードはasync functions でのみ使用されますが、キーワードyieldはジェネレータfunction*s でのみ使用されます。また、それらも明らかに異なります。一方はプロミスを返し、もう一方はジェネレーターを返します。

await常に何かを約束に変えますが、yieldそのような保証はしませんか?

はい、待っている値awaitを呼び出します。Promise.resolve

yieldジェネレータの外で値を生成するだけです。

于 2016-03-24T11:26:10.453 に答える
0

yield+ -as-a-language-feature は、抽象化gen.next()された基礎となる制御フローを記述する (または実装する) ために使用できます。await-async


他の回答が示唆するように、await-as-a-language-feature は の上に実装されています (または考えることができます) yield

これをより直感的に理解するには、次のようにします。

awaits非同期関数に 42があるとします。await A -> await B -> ...

yield A -> tries resolve this as a Promise深いところでは、 [1]を持つことと同等です。

-> if resolvable, we yield B, and repeat [1] for B

-> if not resolveable, we throw

そのためyields、ジェネレーターでは 42 になります。gen.next()そして、コントローラーでは、完了するか拒否されるまで単純に処理を続けます。await(つまり、これは42 を含む非同期関数で使用するのと同じawaitです。)

これが、redux-saga のような lib がジェネレーターを使用して、promise を saga ミドルウェアにパイプし、すべてを 1 か所で解決する理由です。したがって、 Promise 構造をその評価から切り離し、Free Monadと非常によく似ています。

于 2021-09-04T11:59:10.937 に答える