Async/Menanti Konstruktor Kelas
Pada saat ini, saya'm mencoba untuk menggunakan async/menanti
di dalam kelas fungsi constructor. Ini adalah agar saya bisa mendapatkan kustom e-mail
tag untuk sebuah Elektron proyek I'm bekerja pada.
customElements.define('e-mail', class extends HTMLElement {
async constructor() {
super()
let uid = this.getAttribute('data-uid')
let message = await grabUID(uid)
const shadowRoot = this.attachShadow({mode: 'open'})
shadowRoot.innerHTML = `
<div id="email">A random email message has appeared. ${message}</div>
`
}
})
Pada saat ini namun, proyek ini tidak bekerja, dengan error berikut:
Class constructor may not be an async method
Apakah ada cara untuk menghindari hal ini, sehingga saya dapat menggunakan async/menanti dalam hal ini? Bukan membutuhkan callback atau .maka()?
108
13
Hal ini dapat tidak pernah bekerja.
The
async
kata kunci memungkinkanmenunggu
yang akan digunakan dalam sebuah fungsi ditandai sebagaiasync
tetapi juga mengubah fungsi itu menjadi janji generator. Jadi fungsi ditandai denganasync
akan kembali janji. Konstruktor di sisi lain mengembalikan objek itu adalah membangun. Dengan demikian kita memiliki situasi di mana anda ingin keduanya kembali sebuah objek dan janji: situasi yang mustahil.Anda hanya dapat menggunakan async/menginap di mana anda dapat menggunakan menjanjikan karena mereka pada dasarnya sintaks gula untuk janji-janji. Anda dapat't menggunakan janji-janji dalam sebuah konstruktor karena sebuah konstruktor harus kembali objek yang akan dibangun, bukan janji.
Ada dua pola desain untuk mengatasi hal ini, kedua diciptakan sebelum janji-janji yang berada di sekitar.
init()
fungsi. Ini bekerja sedikit seperti jQuery's.siap()
. Objek yang anda buat hanya dapat digunakan dalam it's sendiriinit
atausiap
fungsi:Penggunaan:
var myObj = new myClass(); myObj.init(function() { // di sini anda dapat menggunakan myObj });
Pelaksanaan:
class myClass { konstruktor () {
}
init (callback) { // lakukan sesuatu async dan panggilan callback: callback.bind(this)(); } }
Penggunaan:
myClass.membangun().maka(fungsi(myObj) { // myObj dikembalikan oleh janji, // tidak oleh konstruktor // atau pembangun });
// dengan async/menunggu:
async function foo () { var myObj = menunggu myClass.membangun(); }
Pelaksanaan:
class myClass { konstruktor (async_param) { if (typeof async_param === 'undefined') { melempar Kesalahan baru('Tidak dapat dipanggil secara langsung'); } }
membangun statis () { kembali doSomeAsyncStuff() .maka(fungsi(async_result){ kembali new myClass(async_result); }); } }
Implementasi dengan async/menunggu:
class myClass { konstruktor (async_param) { if (typeof async_param === 'undefined') { melempar Kesalahan baru('Tidak dapat dipanggil secara langsung'); } }
statis async membangun () { var async_result = menunggu doSomeAsyncStuff(); kembali new myClass(async_result); } }
Catatan untuk memanggil fungsi di dalam fungsi statis.
Ini tidak ada sama sekali hubungannya dengan async konstruktor tapi dengan apa kata kunci
ini
benar-benar berarti (yang mungkin sedikit mengejutkan untuk orang-orang yang berasal dari bahasa yang melakukan auto-resolusi nama metode, yaitu, bahasa yang don't perluini
kata kunci).Yang
ini
kata kunci mengacu pada contoh objek. Tidak kelas. Oleh karena itu anda tidak bisa biasanya menggunakanini
dalam statis fungsi karena fungsi statis tidak terikat untuk setiap objek tetapi terikat langsung ke kelas.Itu adalah untuk mengatakan, dalam kode berikut:
Anda tidak bisa melakukan:
sebaliknya anda perlu menyebutnya sebagai:
Oleh karena itu, kode berikut akan menghasilkan kesalahan:
Untuk memperbaikinya anda dapat membuat
bar
baik reguler fungsi atau metode statis:Anda bisa pasti melakukan hal ini. Pada dasarnya:
untuk membuat kelas menggunakan:
Catatan: Jika anda perlu untuk menggunakan super, anda tidak bisa menyebutnya dalam async callback. Anda harus menyebutnya luar itu jadi solusi ini not 100% sempurna, tapi menurut saya itu cukup idiomatik dan saya menggunakannya sepanjang waktu dalam kode saya.
Berdasarkan komentar anda, anda mungkin harus melakukan apa yang setiap HTMLElement dengan aset loading tidak: membuat konstruktor mulai sideloading tindakan, menghasilkan beban atau kesalahan peristiwa tergantung pada hasil.
Ya, itu berarti menggunakan janji-janji, tapi itu juga berarti "tidak melakukan hal-hal dengan cara yang sama seperti setiap elemen HTML", sehingga anda're di perusahaan yang baik. Misalnya:
ini kicks off asynchronous beban dari sumber aset itu, bila berhasil, berakhir di
onload
dan ketika itu terjadi, berakhir dionerror
. Jadi, membuat kelas anda sendiri melakukan hal ini terlalu:Dan kemudian anda membuat renderLoaded/renderError fungsi berurusan dengan peristiwa panggilan dan bayangan dom:
Juga catatan saya mengubah anda
id
untukkelas
, karena kecuali anda menulis beberapa kode aneh untuk hanya memungkinkan satu contoh dari<e-mail>
elemen pada halaman, anda dapat't menggunakan pengidentifikasi unik dan kemudian menetapkan untuk sekelompok elemen.Karena async fungsi yang menjanjikan, anda dapat membuat fungsi statis di kelas anda yang mengeksekusi async function yang mengembalikan instance dari kelas:
Sebut dengan
biarkan yql = menunggu Yql.init()
dari sebuah async function.menggunakan async metode dalam membangun???
Saya membuat ini test-case based on @Downgoat's jawaban. Ini berjalan pada NodeJS. Ini adalah Downgoat's kode async bagian ini disediakan oleh
setTimeout()
call.Saya menggunakan hal ini DAOs untuk sisi server aplikasi web. Seperti yang saya lihat DAOs, mereka masing-masing terkait dengan format record, dalam kasus saya MongoDB koleksi seperti misalnya memasak. Sebuah cooksDAO contoh memegang memasak's data. Dalam pikiran gelisah saya, saya akan mampu untuk instantiate memasak's DAO menyediakan cookId sebagai argumen, dan instansiasi akan membuat objek dan mengisinya dengan memasak's data. Dengan demikian perlu untuk menjalankan async barang-barang ke konstruktor. Aku ingin menulis:
untuk memiliki properti yang tersedia seperti
memasak.getDisplayName()
. Dengan solusi ini harus saya lakukan:yang sangat mirip dengan ideal. Juga, aku harus melakukan ini dalam sebuah
async
fungsi.Saya B-rencana untuk meninggalkan loading data dari konstruktor, berdasarkan @slebetman saran untuk menggunakan fungsi init, dan melakukan sesuatu seperti ini:
yang doesn't melanggar aturan.
Jika anda dapat menghindari
memperpanjang
, anda dapat menghindari semua kelas bersama-sama dan menggunakan fungsi komposisi sebagai constructors. Anda dapat menggunakan variabel-variabel dalam lingkup yang bukan anggota kelas:js async function buildA(...) { const data = menunggu fetch(...); kembali { getData: fungsi() { mengembalikan data; } } }
dan sederhana menggunakannya sebagai
js const a = menunggu buildA(...);
Jika anda're menggunakan naskah atau aliran, anda bahkan dapat menegakkan antarmuka constructors `` Antarmuka { getData: objek; }
async function buildA0(...): Janji { ... } async function buildA1(...): Janji { ... } ... ``
Anda dapat membuat sebuah
async init() {... kembali ini;}
metode, maka bukan tidaknew MyClass().init()
setiap kali anda'd biasanya hanya mengatakannew MyClass()
.Ini tidak bersih karena hal itu bergantung pada setiap orang yang menggunakan kode anda, dan diri anda sendiri, untuk selalu instantiate obyek seperti begitu. Namun jika anda're hanya menggunakan objek ini di tempat tertentu atau dua dalam kode anda, hal itu harus baik-baik saja.
Anda dapat segera memanggil anonim async function yang mengembalikan pesan dan set ke pesan variabel. Anda mungkin ingin mengambil melihat segera dipanggil fungsi ekspresi (IEFES), dalam kasus anda tidak terbiasa dengan pola ini. Ini akan bekerja seperti pesona.
Variasi pada pembangun pola, menggunakan panggilan():
@slebetmen's jawaban yang diterima menjelaskan dengan baik mengapa hal ini doesn't bekerja. Selain dua pola yang disajikan dalam jawaban itu, pilihan lain adalah untuk hanya mengakses async sifat melalui custom async getter. Konstruktor() kemudian dapat memicu async penciptaan sifat, tetapi pengambil kemudian memeriksa untuk melihat jika properti yang tersedia sebelum menggunakan atau kembali.
Pendekatan ini sangat berguna ketika anda ingin menginisialisasi sebuah objek global setelah pada startup, dan anda ingin melakukannya di dalam sebuah modul. Bukan inisialisasi dalam
index.js
dan melewati misalnya di tempat-tempat yang membutuhkannya, hanyamemerlukan
modul anda dimanapun global objek yang dibutuhkan.Penggunaan
Implementasi
Anda harus menambahkan
kemudian
fungsi untuk contoh.Berjanji
akan mengenali ini sebagai thenable objek dengan Janji.mengatasi
secara otomatisLain jawaban yang hilang yang jelas. Hanya panggilan async fungsi dari constructor: