Apa yang terjadi ketika modul JS diimpor dua kali?

Mari kita mulai artikel ini dengan sebuah pertanyaan. Modul ES2015 incrementberisi kode berikut:

// increment.js
let counter = 0;
counter++;

export default counter;

Dalam modul lain, yang akan kita panggil consumer, modul di atas diimpor 2 kali:

// consumer.js
import counter1 from './increment';
import counter2 from './increment';

counter1; // => ???
counter2; // => ???

Dan sekarang, sebenarnya, sebuah pertanyaan. Apa yang masuk dalam variabel counter1dan counter2setelah modul consumer? Untuk menjawab pertanyaan ini, Anda perlu memahami bagaimana JavaScript mengeksekusi modul, dan bagaimana mereka diimpor.





Eksekusi modul


Untuk memahami bagaimana mekanisme JavaScript internal berfungsi, penting untuk melihat spesifikasi .

Menurut spesifikasi, setiap modul JavaScript dikaitkan dengan entitas Record Modul . Entri ini memiliki metode Evaluate()yang dijalankan oleh modul:

Jika modul ini telah berhasil dieksekusi, kembalikan tidak terdefinisi; [...] Jika tidak, jalankan semua dependensi dari modul ini secara transparan dan kemudian jalankan modul ini.
Hasilnya, ternyata modul yang sama dijalankan hanya sekali.

Sayangnya, apa yang perlu Anda ketahui untuk menjawab pertanyaan kami tidak terbatas pada ini. Cara memastikan bahwa panggilan instruksiimport menggunakan jalur yang sama akan mengembalikan modul yang sama?

Izinkan perintah impor


Operasi abstrak HostResolveImportedModule () bertanggung jawab untuk mengaitkan path ke modul (specifier) ​​dengan modul tertentu . Kode impor modul terlihat seperti ini:

import module from 'path';

Berikut adalah apa yang dikatakan oleh spec tentang itu:

Implementasi HostResolveImportedModule harus memenuhi persyaratan berikut:

  • Nilai pengembalian normal harus merupakan turunan dari subkelas tertentu dari Catatan Modul.
  • Jika entitas Record Modul yang sesuai dengan pasangan referensi ScriptOrModule, specifier tidak ada, atau entitas seperti itu tidak dapat dibuat, pengecualian harus dilemparkan.
  • Setiap kali operasi ini dipanggil dengan memberikannya sebagai argumen sepasang referensiencingScriptOrModule, specifier, ia harus, dalam kasus eksekusi yang biasa, mengembalikan instance yang sama dari entitas Record Modul.

Sekarang pertimbangkan ini dengan cara yang lebih dimengerti.

HostResolveImportedModule(referencingScriptOrModule, specifier)- sebuah operasi abstrak yang kembali modul sesuai dengan sepasang parameter referencingScriptOrModule, specifier:

  • Parameternya referencingScriptOrModuleadalah modul saat ini, yaitu modul yang mengimpor.
  • Parameter specifieradalah string yang cocok dengan lintasan modul dalam instruksi import.

Pada akhir deskripsi, HostResolveImportedModule()dikatakan bahwa ketika mengimpor modul yang sesuai dengan jalur yang sama, modul yang sama diimpor:

import moduleA from 'path';
import moduleB from 'path';
import moduleC from 'path';

// moduleA, moduleB  moduleC -    

moduleA === moduleB; // => true
moduleB === moduleC; // => true

Menariknya, spesifikasi menunjukkan bahwa host (browser, lingkungan Node.js, secara umum - apa pun yang mencoba mengeksekusi kode JavaScript) harus menyediakan implementasi spesifik HostResolveImportedModule().

Menjawab


Setelah membaca spesifikasi dengan cermat, menjadi jelas bahwa modul JavaScript dieksekusi hanya sekali selama impor. Dan ketika mengimpor modul menggunakan jalur yang sama, instance modul yang sama dikembalikan.

Mari kita kembali ke pertanyaan kita.

Modul incrementselalu dijalankan hanya sekali:

// increment.js
let counter = 0;
counter++;

export default counter;

Terlepas dari berapa kali modul diimpor increment, ekspresi counter++hanya dievaluasi satu kali. Variabel yang counterdiekspor menggunakan mekanisme ekspor standar penting 1.

Sekarang lihat modul consumer:

// consumer.js
import counter1 from './increment';
import counter2 from './increment';

counter1; // => 1
counter2; // => 1

Perintah import counter1 from './increment'dan import counter2 from './increment'gunakan jalur yang sama - './increment'. Hasilnya, ternyata instance modul yang sama diimpor.

Ternyata nilai yang sama 1 ditulis ke variabel counter1dan counter2ke consumer.

Ringkasan


Setelah memeriksa pertanyaan sederhana, kami dapat mengetahui lebih lanjut tentang bagaimana modul JavaScript dieksekusi dan diimpor.

Aturan yang digunakan saat mengimpor modul cukup sederhana: modul yang sama dijalankan hanya sekali. Dengan kata lain, apa yang ada dalam lingkup level modul hanya dilakukan sekali. Jika modul yang sudah dijalankan sekali diimpor kembali, maka tidak akan dieksekusi lagi. Saat mengimpor modul, modul ini menggunakan apa yang diperoleh sebagai hasil dari sesi sebelumnya untuk mengetahui apa yang sebenarnya diekspor.

Jika suatu modul diimpor beberapa kali, tetapi penentu modul (jalur ke sana) tetap sama, spesifikasi JavaScript memastikan bahwa instance modul yang sama diimpor.

Pembaca yang budiman! Seberapa sering Anda resor untuk membaca spesifikasi JavaScript, mencari tahu fitur fungsi konstruksi bahasa tertentu?


All Articles