您來到這裡是因為您有一個問題:我如何等待類別建構子?如何使構造函數異步? ? ?
很抱歉,答案是你確實不能。 Javascript 中類別的建構子必須是同步的。但是,實作中存在一些替代方案可以幫助您完成您想要的操作。讓我們來探索一下吧!
您可能需要這個,因為您需要在建構函式中初始化某些內容,並使其在對類別進行的任何呼叫中可用。一個很好的例子是連接到資料庫並在接受任何查詢之前等待該連接建立。
這個模式非常簡單!讓我們從一個範例資料庫連接器開始,使用 npm 上的 sqlite 模組:
import sqlite3 from 'sqlite3'; import { open } from 'sqlite';
要開啟此資料庫,您需要等待 open 函數。我讓我友好的 AI 代碼助手想出了一個“DBConnector”類,它實際上得到了正確的通用模式 - 你隨處可見的模式:
class DBConnector { constructor() { this.db = null; } async connect() { this.db = await open({ filename: './database.sqlite', driver: sqlite3.Database, }); } async disconnect() { await this.db.close(); } async query(sql, params) { return this.db.all(sql, params); } } // exporting a singleton so there's only one connection export default new DBConnector();
您只需匯入它然後等待它的呼叫即可呼叫它:
import db from './dbconnector.js'; await db.connect(); await db.query('GET * FROM test');
所以現在,這裡的問題當然是,你不僅需要手動調用myDB.connect() 來啟動連接,你也不能保證查詢調用能夠工作,比如說,如果當您的主文件正在連接時,另一個文件會執行查詢。
當然,主檔案可以await db.connect(); ,但是導入此模組的任何其他內容都沒有任何方法可以做到這一點。您可能會想,「好吧,但我也可以在其他檔案中呼叫wait db.connect();,對嗎?」你可以...但是每次都會重新連接到資料庫,這可能會很慢,具體取決於你使用的是什麼。
我想出來的模式稍微複雜一點,但它仍然很簡單,並確保每一小段程式碼 - 以及你自己 - 都滿意。事實上,這是我自己想出來的,即使它實際上為其他人所知。它們被稱為「延期」承諾。
這是它的工作原理。
// still have our imports import sqlite3 from 'sqlite3'; import { open } from 'sqlite'; // Create the class class DBConnector { // We'll need these private properties: #db; #defer; #resolve; #reject; // Then we make our constructor: constructor() { // We create a new promise and store its resolve and reject // functions in the class instance properties. this.#defer = new Promise((res, rej) => { // this is the magic, right here, basically. this.#resolve = res; this.#reject = rej; }); // So now, this.#defer is a promise! We can await it in other methods. // Now we call our this.connect *internally* and automatically. this.connect(); } async connect() { try { this.#db = await open({ filename: `./database.sqlite`, driver: sqlite3.Database, }); // Now that we resolve the promise, any other method that awaits // this.#defer will continue executing. this.#resolve(); } catch (err) { // in case of error we can of course reject the promise // any code using it would then throw an error. this.#reject(err); } } async disconnect() { // on any action, we just await this.#defer await this.#defer; await this.#db.close(); } async query(sql, params) { // Even in queries, it works perfectly fine! await this.#defer; // Here we KNOW that this.#db is already initialized. return this.#db.all(sql, params); } } export default new DBConnector();
這不是一個迷人的小圖案嗎?當然,這是一個比基本範例更多的程式碼,但就我個人而言,我認為它肯定提高了主要基於非同步方法的類別的樣板程式碼的標準。
讓我們看看如何使用它!
import db from './dbconnector.js'; // it's already initialized... just use it! await db.query('GET * FROM test'); // and it just works :D
我經常使用這種模式,最終我決定製作一個非常快速且骯髒的庫並將其發佈到 NPM 上。它被稱為延遲,使用起來非常簡單(一旦我知道了模式,編寫起來也非常簡單)。
讓我們使用延遲來重新製作上面的範例。
import sqlite3 from 'sqlite3'; import { open } from 'sqlite';
「db」字串基本上是您想要賦予延遲的任何字串名稱,您可以建立任意多個。顯然你不需要需要這個庫,但我個人認為它非常好,你知道嗎?
我希望您在這裡學到了真正有用的模式,我很高興能成為您今天學習之旅的一部分
以上是如何在 Javascript 中建立非同步建構函數?的詳細內容。更多資訊請關注PHP中文網其他相關文章!