Rumah  >  Artikel  >  hujung hadapan web  >  Satu artikel untuk memahami modularisasi es6 secara menyeluruh

Satu artikel untuk memahami modularisasi es6 secara menyeluruh

藏色散人
藏色散人ke hadapan
2023-02-17 11:17:592399semak imbas

Semakan situasi sebelum ini

  • Kami telah bercakap tentang CommonJs dalam artikel yang lepas Jika anda belum membacanya, anda boleh mencari ruangan di mana artikel ini berada untuk belajar.
  • CommonJs mempunyai banyak ciri yang sangat baik, mari kita semak secara ringkasnya di bawah:
  • Kod modul hanya dijalankan selepas dimuatkan;

  • Modul hanya boleh dimuatkan sekali sahaja;

  • Modul boleh meminta untuk memuatkan modul lain;

  • Menyokong kebergantungan pekeliling;

  • Modul boleh mentakrifkan antara muka awam, dan modul lain boleh memerhati dan berinteraksi berdasarkan antara muka awam ini >

  • adalah unik kerana ia boleh dimuatkan secara asli melalui penyemak imbas atau dengan pemuat pihak ketiga dan alat binaan.

Penyemak imbas yang menyokong modul

boleh memuatkan keseluruhan graf pergantungan daripada modul peringkat atas secara tidak segerak. Penyemak imbas akan menghuraikan modul kemasukan, menentukan kebergantungan, dan menghantar permintaan untuk modul bergantung. Selepas fail ini dikembalikan melalui rangkaian, penyemak imbas akan menyelesaikan kebergantungan mereka, dan jika kebergantungan sekunder ini belum dimuatkan, lebih banyak permintaan akan dihantar.
  • Proses pemuatan rekursif tak segerak ini akan diteruskan sehingga keseluruhan graf pergantungan aplikasi telah diselesaikan. Selepas graf pergantungan dihuraikan, program rujukan boleh memuatkan modul secara rasmi. Es Module
  • bukan sahaja meminjam banyak ciri cemerlang Es module dan
  • , tetapi juga menambah beberapa gelagat baharu:
  • Es ModuleCommonJsAMD Lalai Dilaksanakan dalam mod ketat;
  • tidak berkongsi ruang nama global; 🎜> ialah Es Module (Skrip biasa ialah

    ); 🎜>
  • dimuatkan dan dilaksanakan secara tak segerak;

    . Perintah Es Module

  • digunakan untuk menentukan antara muka luaran modul, dan perintah
  • digunakan untuk memasukkan fungsi yang disediakan oleh modul lain.

    Es ModulethisPenggunaan asas eksportundefinedwindow

    Bentuk asas eksport:
  • varwindowSudah tentu, anda juga boleh menulisnya seperti berikut Borang:

  • Es Module mengeksport objek dan fungsi

Biasanya, output pembolehubah oleh
    ialah Nama asal boleh dinamakan semula menggunakan kata kunci
  • . exportsimport
  • exportEksport lalai perlu diambil perhatian bahawa modul hanya boleh mempunyai satu eksport lalai: import

Penggunaan eksport yang salah

    Pernyataan eksport mesti berada di peringkat atas modul dan tidak boleh bersarang dalam blok:
export const nickname = "moment";
export const address = "广州";
export const age = 18;
  • Antara muka luaran mesti disediakan:
const nickname = "moment";
const address = "广州";
const age = 18;

export { nickname, address, age };
    Penggunaan asas import
Selepas menggunakan perintah
export function foo(x, y) {
  return x + y;
}

export const obj = {
  nickname: "moment",
  address: "广州",
  age: 18,
};

// 也可以写成这样的方式
function foo(x, y) {
  return x + y;
}

const obj = {
  nickname: "moment",
  address: "广州",
  age: 18,
};

export { foo, obj };
untuk menentukan antara muka luaran modul, fail js lain boleh memuatkan keseluruhan modul melalui perintah
  • exportas
Pengecam modul boleh menjadi laluan relatif kepada modul semasa, laluan mutlak atau rentetan tulen, tetapi ia tidak boleh menjadi hasilnya pengiraan dinamik, seperti rentetan dengan .
const address = "广州";
const age = 18;

export { nickname as name, address as where, age as old };
  • Perintah menerima pendakap kerinting, yang menentukan nama pembolehubah untuk diimport daripada modul lain dan nama pembolehubah mestilah sama dengan nama antara muka luaran modul yang diimport.
Pembolehubah yang diimport tidak boleh ditetapkan semula kerana ia adalah antara muka baca sahaja Jika ia objek, sifat objek boleh ditetapkan semula. Modul yang dieksport boleh mengubah suai nilai, dan pembolehubah yang diimport juga akan berubah dengan sewajarnya.
export default "foo";

export default { name: 'moment' }

export default function foo(x,y) {
  return x+y
}

export { bar, foo as default };

    • 从上图可以看得出来,对象的属性被重新赋值了,而变量的则报了 Assignment to constant variable 的类型错误。
    • 如果模块同时导出了命名导出和默认导出,则可以在 import 语句中同时取得它们。可以依次列出特定的标识符来取得,也可以使用 * 来取得:
    // foo.js
    export default function foo(x, y) {
      return x + y;
    }
    
    export const bar = 777;
    
    export const baz = "moment";
    
    // main.js
    import { default as foo, bar, baz } from "./foo.js";
    
    import foo, { bar, baz } from "./foo.js";
    
    import foo, * as FOO from "./foo.js";

    动态 import

    • 标准用法的 import 导入的模块是静态的,会使所有被导入的模块,在加载时就被编译(无法做到按需编译,降低首页加载速度)。有些场景中,你可能希望根据条件导入模块或者按需导入模块,这时你可以使用动态导入代替静态导入。
    • 关键字 import 可以像调用函数一样来动态的导入模块。以这种方式调用,将返回一个 promise
    import("./foo.js").then((module) => {  const { default: foo, bar, baz } = module;  console.log(foo); // [Function: foo]
      console.log(bar); // 777
      console.log(baz); // moment});复制代码

    使用顶层 await

    • 在经典脚本中使用 await 必须在带有 async 的异步函数中使用,否则会报错:
    import("./foo.js").then((module) => {
      const { default: foo, bar, baz } = module;
      console.log(foo); // [Function: foo]
      console.log(bar); // 777
      console.log(baz); // moment
    });
    • 而在模块中,你可以直接使用 Top-level await:
    const p = new Promise((resolve, reject) => {  resolve(777);
    });const result = await p;console.log(result); 
    // 777正常输出

    import 的错误使用

    • 由于import是静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构。
    // 错误
    import { 'b' + 'ar' } from './foo.js';
    
    // 错误
    let module = './foo.js';
    import { bar } from module;
    
    // 错误
    if (x === 1) {
      import { bar } from './foo.js';
    } else {
      import { foo } from './foo.js';
    }

    在浏览器中使用 Es Module

    • 在浏览器上,你可以通过将 type 属性设置为 module 用来告知浏览器将 script 标签视为模块。
    <script></script><script></script>
    • 模块默认情况下是延迟的,因此你还可以使用 defer 的方式延迟你的 nomodule 脚本:
      <script>      
      console.log("模块情况下的");
        </script>    
        <script></script>
        <script>
          console.log("正常 script标签");    
          </script>

    Satu artikel untuk memahami modularisasi es6 secara menyeluruh

    • 在浏览器中,引入相同的 nomodule 脚本会被执行多次,而模块只会被执行一次:
        <script></script>    <script></script>
    
        <script></script>
        <script></script>
        <script></script>

    Satu artikel untuk memahami modularisasi es6 secara menyeluruh

    模块的默认延迟

    • 默认情况下,nomodule 脚本会阻塞 HTML 解析。你可以通过添加 defer 属性来解决此问题,该属性是等到 HTML 解析完成之后才执行。

    Satu artikel untuk memahami modularisasi es6 secara menyeluruh

    • defer dan async adalah atribut pilihan mereka hanya boleh memilih salah satu daripadanya Di bawah skrip nomodule, defer tidak akan menghuraikan skrip semasa sehingga HTML dihuraikan, manakala <.> akan dihuraikan selari dengan async dan tidak akan menyekat penghuraian HTML Skrip modul boleh menentukan atribut HTML, tetapi ia tidak sah untuk async kerana modul ditangguhkan secara lalai. defer
    • Untuk skrip modul, jika atribut
    • hadir, skrip modul dan semua kebergantungannya akan dihuraikan dan diambil secara selari, dan skrip modul akan dilaksanakan sebaik sahaja ia tersedia. async
    Perbezaan antara Modul Es dan Commonjs

      Sebelum membincangkan modul
    • , anda mesti terlebih dahulu memahami bahawa Es Module berbeza sepenuhnya daripada Es Module mempunyai tiga mata yang berbeza sama sekali: Commonjs
    1. Modul mengeluarkan salinan nilai, CommonJS mengeluarkan rujukan kepada nilai; modul dimuatkan pada masa jalan, Es Module ialah antara muka output masa kompilasi. Modul
    2. CommonJS Es Module adalah untuk memuatkan modul secara serentak, dan perintah
    3. modul ES6 adalah untuk memuatkan secara tak segerak, dengan fasa resolusi bebas untuk kebergantungan modul.
    4. CommonJSrequire()importPerbezaan kedua ialah kerana
    5. memuatkan objek (iaitu atribut
    ), yang hanya akan dijana selepas skrip dijalankan. Dan
      bukan objek antara muka luarannya hanyalah definisi statik, yang akan dijana semasa fasa analisis statik kod.
    • CommonJSmodule.exports Apa itu output ialah salinan nilai, maksudnya, apabila nilai dikeluarkan, perubahan dalam modul tidak akan menjejaskan nilai. Untuk butiran, sila lihat artikel sebelum ini. Es Module
    • beroperasi secara berbeza daripada Commonjs.
    • Apabila menganalisis skrip secara statik, rujukan baca sahaja akan dijana apabila arahan memuatkan modul
    • ditemui. Apabila skrip benar-benar dilaksanakan, nilai akan diambil daripada modul yang dimuatkan berdasarkan rujukan baca sahaja ini. Dalam erti kata lain, Es Module ialah paip sambungan Jika nilai asal berubah, nilai yang dimuatkan oleh CommonJS juga akan berubah dengan sewajarnya. Oleh itu, JS引擎 ialah rujukan dinamik dan nilai tidak akan dicache Pembolehubah dalam modul terikat pada modul di mana ia berada. importimportimportKonsep berkaitan prinsip kerja Modul EsEs Module
    Sebelum mempelajari prinsip kerja, kita juga boleh mengetahui konsep yang berkaitan.

      Rekod Modul
    Rekod Modul (

    ) merangkum maklumat struktur tentang import dan eksport modul tunggal (modul semasa). Maklumat ini digunakan untuk memautkan import dan eksport set modul sambungan. Rekod modul terdiri daripada empat medan, yang hanya digunakan semasa melaksanakan modul. Empat medan tersebut ialah:

    • Module Record
    • : Buat skop modul semasa
    1. : Rekod persekitaran pengikatan peringkat atasan; modul, Medan ini ditetapkan apabila modul dipautkan; Realm
    2. : Objek ruang nama modul ialah objek asing ruang nama modul yang menyediakan akses berasaskan sifat masa jalan kepada pengikatan eksport modul. Objek ruang nama modul tidak mempunyai pembina; Environment
    3. : medan dikhaskan untuk digunakan sebagai Namespace dan memerlukan maklumat tambahan untuk dikaitkan dengan modul.
    4. HostDefinedRekod Persekitaran Modulhost environments
    Rekod persekitaran modul ialah rekod persekitaran deklaratif yang digunakan untuk mewakili skop luaran modul ECMAScript. Selain pengikatan boleh ubah dan tidak berubah biasa, rekod persekitaran modul juga menyediakan pengikatan

    tidak berubah, yang menyediakan akses tidak langsung kepada pengikatan sasaran yang wujud dalam rekod persekitaran lain.

    • importIkatan tidak berubah bermakna modul semasa memperkenalkan modul lain, dan pembolehubah yang diperkenalkan tidak boleh diubah suai Ini ialah pengikatan tidak berubah unik bagi modul.
    • Proses penghuraian Modul Es

      • Sebelum kita mula, mari kita ambil gambaran kasar tentang keseluruhan proses Mari kita fahami secara umum:
    1. Fasa 1: Pembinaan (Construction), cari fail js mengikut alamat, muat turun melalui rangkaian, dan huraikan fail modul ke Module Record;
    2. Fasa 2: Instantiation (Instantiation), instantiate modul, peruntukkan ruang memori, huraikan penyataan import dan eksport modul, dan halakan modul ke alamat memori yang sepadan; >), jalankan kod, Kira nilai dan isikan nilai ke dalam alamat memori; modul. Mula-mula kita mengubah suai fail masukan, yang biasanya merupakan tag
    3. dalam
    4. untuk mewakili fail modul. Evaluation

    • Modul terus diisytiharkan melalui pernyataan loader, dan terdapat pengecam pengisytiharan modul (HTML) dalam <script type="module"></script> pernyataan pengisytiharan, yang Beritahu
    • cara mencari alamat modul seterusnya.

    Satu artikel untuk memahami modularisasi es6 secara menyeluruh

    • importSetiap nombor pengenalan modul sepadan dengan import dan setiap ModuleSpecifier termasuk loader,
    • ,
    ,

    , Satu artikel untuk memahami modularisasi es6 secara menyeluruh,

    . Di mana nilai
      ialah jenis
    • dan 模块记录(Module Record), 模块记录, JavaScript代码 ialah jenis 执行上下文. ImportEntriesLocalExportEntriesIndirectExportEntriesRekod ImportEntryStarExportEntriesImportEntriesImportEntry RecordsA LocalExportEntries mengandungi tiga medan IndirectExportEntries, StarExportEntries, ExportEntry Records;

    ModuleRequest: pengecam modul (
      );
    • ImportEntry RecordsImportName: nama pengikatan yang diperlukan yang dieksport oleh modul dengan pengecam modul ModuleRequest. Nilai ImportName menunjukkan bahawa permintaan import adalah untuk objek ruang nama modul sasaran; >LocalName
    • Untuk butiran, sila rujuk gambar di bawah:
    1. Jadual berikut merekodkan contoh medan ModuleSpecifier yang diimport menggunakan
    2. :
    3. ModuleRequestnamespace-object

      Rekod ExportEntry

      • A ExportEntry Records mengandungi empat medan ExportName, ModuleRequest, ImportName, LocalName, perbezaan daripada ImportEntry Records ialah terdapat satu lagi ExportName.
      1. ExportName: Modul ini digunakan untuk mengikat nama semasa mengeksport.
      • Jadual berikut merekodkan contoh medan export yang dieksport menggunakan ExportEntry Records:

        导出声明 导出名 模块标识符 导入名 本地名
        export var v; "v" null null "v"
        export default function f() {} "default" null null "f"
        export default function () {} "default" null null "default"
        export default 42; "default" null null "default"
        export {x}; "x" null null "x"
        export {v as x}; "x" null null "v"
        export {x} from "mod"; "x" "mod" "x" null
        export {v as x} from "mod"; "x" "mod" "v" null
        export * from "mod"; null "mod" all-but-default null
        export * as ns from "mod"; "ns "mod" all null
      • Kembali ke topik

      • Hanya selepas menghuraikan semasa Module Record boleh anda tahu submodul yang mana modul semasa bergantung, dan kemudian anda perlu resolve Sub-modul, dapatkan sub-modul, kemudian huraikan sub-modul, teruskan kitaran proses ini menyelesaikan -> menguraikan -> >

      Satu artikel untuk memahami modularisasi es6 secara menyeluruhProses ini juga dipanggil

      dan tidak menjalankan kod JavaScript Ia hanya mengenali kata kunci
        dan
      • , jadi 静态分析 tidak boleh. digunakan dalam skop bukan global , kecuali import dinamik. exportimportBagaimana jika berbilang fail bergantung pada satu fail serentak? import
      • Gunakan
      • untuk menjejak dan cache global
      • untuk memastikan modul hanya loader sekali, dan akan ada Peta Modul bebas dalam setiap skop global. Module MapMOdule Recordfetch
      • Peta MODUL ialah objek pemetaan kunci/nilai yang terdiri daripada rekod URL dan rentetan. Rekod URL ialah URL permintaan untuk mendapatkan modul, rentetan yang menunjukkan jenis modul (mis. "javascript"). Nilai peta modul ialah sama ada skrip modul, null (digunakan untuk menunjukkan pengambilan yang gagal) atau nilai pemegang tempat "mengambil".

      fasa pemautan pemautanSatu artikel untuk memahami modularisasi es6 secara menyeluruh

      Selepas semua

      dihuraikan, enjin JS perlu memautkan semua modul . Enjin JS mengambil
        fail kemasukan sebagai titik permulaan, memautkan modul secara rekursif dalam susunan mendalam-dahulu dan mencipta
      • untuk setiap Module Record untuk mengurus pembolehubah dalam Module Record. Terdapat Module Record dalam Module Environment RecordModule Record

      Satu artikel untuk memahami modularisasi es6 secara menyeluruh

        , yang digunakan untuk menyimpan pembolehubah yang dieksport oleh
      • , seperti yang ditunjukkan dalam rajah di atas. Pembolehubah Module Environment Record dieksport pada modul Binding, dan akan terdapat Module Record dalam main.js dalam count Pada masa ini, ia bersamaan dengan fasa kompilasi Module Environment Record, mewujudkan a objek contoh modul , tambahkan atribut dan kaedah yang sepadan, nilainya ialah Binding atau count pada masa ini, dan peruntukkan ruang memori untuknya. V8undefined menggunakan kata kunci null dalam submodul
      • untuk mengimport
      • , dan lokasi memori yang ditunjuk oleh pembolehubah count.js import dan main.js's count.js adalah konsisten, sekali gus menghubungkan hubungan antara modul ibu bapa dan anak. Seperti yang ditunjukkan dalam gambar di bawah:importmain.jsexport
      • 需要注意的是,我们称 export 导出的为父模块,import 引入的为子模块,父模块可以对变量进行修改,具有读写权限,而子模块只有读权限。

      Evaluation 求值阶段

      • 在模块彼此链接完之后,执行对应模块文件中顶层作用域的代码,确定链接阶段中定义变量的值,放入内存中。

      Es module 是如何解决循环引用的

      • Es Module 中有5种状态,分别为 unlinkedlinkinglinkedevaluatingevaluated,用循环模块记录(Cyclic Module Records)的 Status 字段来表示,正是通过这个字段来判断模块是否被执行过,每个模块只执行一次。这也是为什么会使用 Module Map 来进行全局缓存 Module Record 的原因了,如果一个模块的状态为 evaluated,那么下次执行则会自动跳过,从而包装一个模块只会执行一次。 Es Module 采用 深度优先 的方法对模块图进行遍历,每个模块只执行一次,这也就避免了死循环的情况了。

      深度优先搜索算法(英语:Depth-First-Search,DFS)是一种用于遍历或搜索树或图的算法。这个算法会尽可能深地搜索树的分支。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。

      Satu artikel untuk memahami modularisasi es6 secara menyeluruh

      • 看下面的例子,所有的模块只会运行一次:
      // main.js
      import { bar } from "./bar.js";
      export const main = "main";
      console.log("main");
      
      // foo.js
      import { main } from "./main.js";
      export const foo = "foo";
      console.log("foo");
      
      // bar.js
      import { foo } from "./foo.js";
      export const bar = "bar";
      console.log("bar");
      • 通过 node 运行 main.js ,得出以下结果:

      Satu artikel untuk memahami modularisasi es6 secara menyeluruh

Atas ialah kandungan terperinci Satu artikel untuk memahami modularisasi es6 secara menyeluruh. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:juejin.im. Jika ada pelanggaran, sila hubungi admin@php.cn Padam