コンストラクター関数が Promise を返すのは悪い習慣ですか? 質問する

コンストラクター関数が Promise を返すのは悪い習慣ですか? 質問する

ブログ プラットフォームのコンストラクターを作成しようとしていますが、その内部では多くの非同期操作が行われています。これには、ディレクトリからの投稿の取得、解析、テンプレート エンジンを介した送信などが含まれます。

そこで私の質問は、コンストラクター関数が、呼び出された関数のオブジェクトではなく、Promise を返すようにするのは賢明ではないかどうかということですnew

例えば:

var engine = new Engine({path: '/path/to/posts'}).then(function (eng) {
   // allow user to interact with the newly created engine object inside 'then'
   engine.showPostsOnOnePage();
});

今、ユーザーはないサプリメントを供給する約束のチェーンリンク:

var engine = new Engine({path: '/path/to/posts'});

// ERROR
// engine will not be available as an Engine object here

これは、ユーザーがなぜ混乱するのかという問題を引き起こす可能性があります。 engine 施工後はご利用いただけません。

コンストラクターで Promise を使用する理由は理にかなっています。構築フェーズ後にブログ全体が機能するようにしたいのですが、 を呼び出した後すぐにオブジェクトにアクセスできないのは、何かおかしい気がしますnew

代わりに Promise を返す や のようなものをengine.start().then()使用することを検討しました。しかし、それらも怪しいようです。engine.init()

編集: これは Node.js プロジェクト内にあります。

ベストアンサー1

はい、それは悪い習慣です。コンストラクタはクラスのインスタンスを返すだけで、それ以外は返しません。そうしないと、newオペレーターそして継承。

さらに、コンストラクタは新しいインスタンスを作成して初期化するだけでよい。データ構造とインスタンス固有のプロパティを設定する必要があるが、実行しないタスクは何でもいいです。純粋関数可能であれば副作用がなく、そのメリットをすべて享受できるもの。

コンストラクターから何かを実行したい場合はどうすればよいでしょうか?

これはクラスのメソッドに記述する必要があります。グローバル状態を変更したいですか? その場合は、オブジェクト生成の副作用としてではなく、その手順を明示的に呼び出します。この呼び出しはインスタンス化の直後に実行できます。

var engine = new Engine();
engine.displayPosts();

そのタスクが非同期の場合、メソッドからその結果の Promise を簡単に返して、完了するまで簡単に待機できます。
ただし、メソッドが (非同期的に) インスタンスを変更し、他のメソッドがそれに依存している場合は、このパターンはお勧めしません。待機が必要になり (実際には同期している場合でも非同期になる)、すぐに内部キュー管理が行われるようになるためです。インスタンスが存在するが実際には使用できないようにコーディングしないでください。

インスタンスにデータを非同期的にロードしたい場合はどうすればよいでしょうか?

自問してみてください:データのないインスタンスが本当に必要ですか? 何らかの方法で使用できますか?

その答えがいいえの場合、データを取得する前に作成しないでください。コンストラクターにデータを取得する方法を指定する (またはデータの promise を渡す) のではなく、データ自体をコンストラクターのパラメーターにします。

次に、静的メソッドを使用してデータを読み込み、そこから Promise を返します。次に、その新しいインスタンスでデータをラップする呼び出しを連鎖します。

Engine.load({path: '/path/to/posts'}).then(function(posts) {
    new Engine(posts).displayPosts();
});

これにより、データを取得する方法の柔軟性が大幅に向上し、コンストラクターが大幅に簡素化されます。同様に、Engineインスタンスの Promise を返す静的ファクトリー関数を記述することもできます。

Engine.fromPosts = function(options) {
    return ajax(options.path).then(Engine.parsePosts).then(function(posts) {
        return new Engine(posts, options);
    });
};


Engine.fromPosts({path: '/path/to/posts'}).then(function(engine) {
    engine.registerWith(framework).then(function(framePage) {
        engine.showPostsOn(framePage);
    });
});

おすすめ記事