paint-brush
Promise、Thenable、遅延評価について知っておくべきこと@austingil
1,653 測定値
1,653 測定値

Promise、Thenable、遅延評価について知っておくべきこと

Austin Gil5m2023/01/20
Read on Terminal Reader

長すぎる; 読むには

新年には、「Promise」をより怠惰にする方法を紹介します。基本的な `Promise' の例を見てみましょう。ここでは、ミリ秒単位の時間と値を取る sleep という関数があります。待機する必要があるミリ秒数の間、`setTimeout` を実行する promise を返します。
featured image - Promise、Thenable、遅延評価について知っておくべきこと
Austin Gil HackerNoon profile picture

新年の始まりです。多くの人がもっとアクティブになることを約束していますが、私はPromiseをもっと怠惰にする方法を紹介します… JavaScript Promise 、つまり。


すぐに理解できるようになります。

まず、基本的なPromiseの例を見てみましょう。ここに、ミリ秒単位の時間と値を取る sleep という関数があります。待機する必要があるミリ秒数の間setTimeoutを実行する promise を返します。 Promise はその値で解決されます。


 /** * @template ValueType * @param {number} ms * @param {ValueType} value * @returns {Promise<ValueType>} */ function sleep(ms, value) { return new Promise((resolve) => { setTimeout(() => resolve(value), ms); }); }


それはこのように動作します:


「await sleep(1000, 'Yawn & Stretch')」というコードを含む JavaScript コンソール。それから1秒後、「『あくびとストレッチ』」


引数1000'Yawn & stretch'を指定してsleep関数を待機すると、1 秒後にconsoleに文字列 'Yawn & Stretch' が記録されます。


それについて特別なことは何もありません。おそらく期待どおりに動作しますが、返されたPromiseをすぐにawaitするのではなく、変数として保存して後でawaitすると、少し奇妙になります。


 const nap = sleep(1000, 'Yawn & stretch')


ここで、時間がかかる他の作業 (次の例を入力するなど) を行い、 await変数をnapするとします。


JavaScript コンソールに「await nap」と入力すると、すぐに「'Yawn & Stretch'」という応答が表示されます。

解決するまでに 1 秒の遅延が予想されるかもしれませんが、実際にはすぐに解決されます。 Promiseを作成するときはいつでも、それが担当する非同期機能をインスタンス化します。


この例では、 nap変数を定義した瞬間に、 setTimeoutを実行するPromiseが作成されます。私はタイピングが遅いので、待機するまでにPromiseawaitされます。


つまり、 Promiseは熱心です。彼らはあなたが彼らをawaitのを待ちません。


場合によっては、これは良いことです。それ以外の場合は、不要なリソースの使用につながる可能性があります。これらのシナリオでは、 Promiseのように見えるものが必要になる場合がありますが、遅延評価必要なときにのみインスタンス化します。


先に進む前に、興味深いことをお見せしたいと思います。


JavaScript でawaitできるのはPromiseだけではありません。 .then()メソッドでプレーンなObjectを作成すると、 awaitと同じように実際にそのオブジェクトをPromiseできます。


テキスト「await { then: () => console.log('🙃') }」の後に「🙃」が続く JavaScript コンソール。

これはちょっと奇妙ですが、 Promiseのように見えてもそうではないさまざまなオブジェクトを作成することもできます。これらのオブジェクトは「セナブルズ」。


それを念頭に置いて、新しいものを作成しましょうクラス組み込みのPromiseコンストラクターを拡張するLazyPromiseと呼ばれます。 Promise の拡張は厳密には必要ではありませんが、 instanceofなどを使用してPromiseに似せたものにします。


 class LazyPromise extends Promise { /** @param {ConstructorParameters<PromiseConstructor>[0]} executor */ constructor(executor) { super(executor); if (typeof executor !== 'function') { throw new TypeError(`LazyPromise executor is not a function`); } this._executor = executor; } then() { this.promise = this.promise || new Promise(this._executor); return this.promise.then.apply(this.promise, arguments); } }


注目すべき部分はthen()メソッドです。標準のPromiseのデフォルトの動作をハイジャックして、実際のPromiseを作成する前に.then()メソッドが実行されるまで待機します。


これにより、実際に呼び出すまで非同期機能のインスタンス化が回避されます。そして、明示的に.then()を呼び出しても、 awaitを使用しても機能します。


それでは、元のsleep関数のPromiseLazyPromiseに置き換えるとどうなるか見てみましょう。もう一度、結果をnap変数に代入します。


 function sleep(ms, value) { return new LazyPromise((resolve) => { setTimeout(() => resolve(value), ms); }); } const nap = sleep(1000, 'Yawn & stretch')


次に、時間をかけてawait nap行を入力して実行します。


JavaScript コンソールに「await nap」と入力すると、1 秒遅れて「'Yawn & Stretch'」という応答が表示されます


今回は、変数が作成されてからの経過時間に関係なく、 Promiseが解決されるまでに 1 秒の遅延が見られます。


(この実装は新しいPromiseを 1 回だけ作成し、その後の呼び出しでそれを参照することに注意してください。したがって、再度awaitすると、通常のPromiseと同様にすぐに解決されます)


もちろん、これは製品コードではおそらく見られない些細な例ですが、遅延評価されたPromiseのようなオブジェクトを使用するプロジェクトはたくさんあります。おそらく最も一般的な例は、データベースORMと次のようなクエリビルダーです。 Knex.jsまたプリズマ.


以下の疑似コードを検討してください。これは、次のクエリ ビルダーのいくつかに触発されています。


 const query = db('user') .select('name') .limit(10) const users = await query


"user"テーブルに移動し、最初の 10 個のエントリを選択してそれらの名前を返すデータベース クエリを作成します。理論的には、これは通常のPromiseでうまく機能します。


しかし、クエリ文字列パラメーターなどの特定の条件に基づいてクエリを変更したい場合はどうすればよいでしょうか?最終的にPromiseを待つ前に、クエリの変更を続行できると便利です。


 const query = db('user') .select('name') .limit(10) if (orderBy) { query.orderBy(orderBy) } if (limit) { query.limit(limit) } if (id) { query.where({ id: id }) } const users = await query


元のデータベース クエリが標準のPromiseである場合、変数を割り当てるとすぐにクエリが積極的にインスタンス化され、後で変更することはできません。


遅延評価を使用すると、このようなコードを記述して、より簡単に追跡でき、開発者のエクスペリエンスが向上し、必要なときに 1 回だけクエリを実行できます。


これは、遅延評価が優れている 1 つの例です。また、HTTP 要求の構築、変更、調整などにも役立つ場合があります。


Lazy Promiseは適切なユースケースには非常に優れていますが、すべてのPromiseを置き換える必要があるとは言えません。場合によっては、積極的にインスタンス化して、できるだけ早く応答を準備することが有益です。


これは、「場合による」シナリオの 1 つです。しかし、次に誰かがあなたにPromiseをするように頼んだら、それについて怠けていると考えてください ( ͡° ͜ʖ ͡°)。


読んでいただきありがとうございます。この記事が気に入ったらどうぞ共有する.それは私をサポートする最良の方法の 1 つです。あなたもすることができますニュースレターにサインアップするまたTwitterで私に従ってください新しい記事が公開されたときに知りたい場合。


最初に公開されたaustingil.com .