web-dev-qa-db-ja.com

JavaScript ES6クラスは非同期コードベースで使用されますか?

ES6 Classes は、組織のパターンとして非同期コードを提供できます。以下はES7 async/awaitの例です。ES6クラスに非同期メソッド、またはES7のコンストラクターを含めることができますか?

僕にできる:

class Foo {
    async constructor() {
        let res = await getHTML();
        this.res = res
    }
}

そして、そうでない場合、コンストラクタはこれをどのように機能させる必要がありますか?

class Foo {
    constructor() {
        getHTML().then( function (res) {
            this.res = res
        }
    }
}

これらのパターンのどちらも機能しない場合、ES6 classのコンストラクター(およびさらにクラス)は、オブジェクトの状態で動作する任意の形式の非同期性をサポートできますか?または、純粋に同期的なコードベース専用ですか?上記の例はコンストラクター内にありますが、そうである必要はありません。問題をもう1レベル下に押し下げます。

class Foo {
    myMethod () {
      /* Can I do anything async here */
    }
}

または、ゲッターを使用して...

class Foo {
    get myProp() {
        /* Is there any case that this is usefully asynchronous */
    }
}

私が考えることができる唯一の例は、同じメソッド/コンストラクタ/ゲッター内で何かを並行して実行することですが、結論の前にすべてを解決することです。完全に非同期のライブラリへのすべてのプッシュでこれが物事を混乱させるのに役立つので、私はちょうど混乱しています。教科書の例を除いて、それらが役に立つアプリケーションを見つけることができません。

53
Evan Carroll

async constructor()はできますか

いいえ、それは構文エラーです-constructor* ()と同じです。コンストラクターは、何も返さない(約束もジェネレーターもない)メソッドであり、インスタンスを初期化するだけです。

そして、そうでない場合、コンストラクターはどのようにこれを行う必要がありますか

このようなコンストラクターはまったく存在すべきではありません。 コンストラクター関数がPromiseを返すのは悪い習慣ですか? を参照してください。

ES6クラスは、オブジェクトの状態で動作する任意の形式の非同期をサポートできますか?または、純粋に同期的なコードベース専用ですか?

はい。クラスで非同期メソッドを(提案されているasync構文でも)使用でき、ゲッターもプロミスを返すことができます。

ただし、一部の非同期プロセスがまだアクティブな状態でメソッドが呼び出された場合に何を行うかを決定する必要があります。すべての操作を順序付けする場合は、インスタンスの状態を、連鎖できるその順序の終了の約束の中に格納する必要があります。または、並列操作を許可する場合、最善の方法は、インスタンスを不変にし、別のインスタンスのプロミスを返すことです。

45
Bergi

ECMAScript 2017は、非同期メソッドのクラスを対象としています。

別の非同期関数またはプロミスを返す関数の呼び出しは、ワンライナーです!

表現力豊かなコードは、実行の遅延に関係なく、上から下まで中断することなく読み取ります

コールバック、代替エラーハンドラ、並列実行、またはその他の満たされていないニーズがある場合は、関数本体でプロミスをインスタンス化します。 promiseエグゼキューターではなく、関数本体にコードを配置することをお勧めします。また、try-catchラッピングコールバックコードがないことに注意してください。

Asyncメソッドは、promise、通常の値、またはthrowを返すことができます

Node.jsの人々が愛していたコールバックAPI、私たちは情熱を持って憎むようになります:それらはすべて約束に包まれなければなりません

Async/awaitの利点は、エラーが暗黙的にバブルアップすることです

class MyClass {
  async doEverything() {
    const sumOfItAll = await http.scrapeTheInternet() +
      await new Promise((resolve, reject) =>
        http.asyncCallback((e, result) => !e ? resolve(result) : reject(e)))
    return this.resp = sumOfItAll
  }
}

ECMAScript 2015に限定され、非同期がない場合、promise値を返します。

class ES2015 {
  fetch(url) {
    return new Promise((resolve, reject) =>
      http.get(url, resolve).on('error', reject))
      .then(resp => this.resp = resp) // plain ECMAScript stores result
      .catch(e => { // optional internal error handler
        console.error(e.message)
        throw e // if errors should propagate
      })
  }
}

このECMAScript 2015バージョンは、あなたが本当に求めているものであり、返されたpromiseコンストラクトを使用して、望ましい動作をコーディングできます。

本当にコンストラクタでプロミスを実行したい場合、消費者がプロミスの履行または拒否に対してアクションを実行できるように、then-catch関数を渡すか、コールバック構造を提供することをお勧めします。コンストラクターでは、実際の作業を行う前にnextTick/.thenを待機することもお勧めします。

すべての約束には最終的なキャッチが必要です。

9
Harald Rudell

クラスが非同期タスクの配置に役立つもう1つの方法は、 静的メソッド を排他的に使用することです。

class Organizer {
    static async foo() {
        const data = await this.bar();
        data.key = value;
        return data;
    }
    static async bar() {
        return {foo:1, bar:2}
    }
};

Organizer.foo();

もちろん、これは単純なオブジェクトリテラルまたは新しいファイルを作成して含めることと同じです。ただし、extend itをよりきれいにできる場合を除きます。

9
Evan Carroll

これは遅い応答ですが、2番目の例が機能しないのは、コンテキストエラーのためです。 function () {}を引数としてPromise.prototype.then()に渡すと、関数内の字句のthisはクラスではなく関数自体になります。これがthis.resの設定が何もしないように見える理由です。その場合、thisは関数自身のスコープを参照します。

Javascriptで外部スコープにアクセスする方法はいくつかあります。古典的な方法(ES5コードでよく見られる方法)は次のとおりです。

class Foo {
  constructor() {
    var _this = this

    getHTML().then(function (res) {
      _this.res = res
    })
  }
}

クラスthisへの参照を作成することにより、内部スコープでアクセスできます。

ES6の方法は 矢印関数 を使用することです。これは新しいスコープを作成せず、現在のスコープを「保持」します。

class Foo {
  constructor() {
    getHTML().then(res => this.res = res)
  }
}

getHTML()がいつ終了したか、さらに悪いことに失敗したかを知る方法がないので、コンテキストの懸念は別として、これは私の意見ではまだ最適な非同期パターンではありません。この問題は async functions でエレガントに解決されます。 async constructor () { ... }は作成できませんが、コンストラクターでpromiseを開始し、それに依存する関数でawaitを開始できます。

例の要点 クラスコンストラクターの非同期プロパティ。

0