成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一篇帶給你 No.js 的模塊加載器實現

開發 前端
因為 JS 本身沒有模塊加載的概念,隨著前端的發展,各種加載技術也發展了起來,早期的seajs,requirejs,現在的 webpack,Node.js等等。

[[424210]]

前言:最近在 No.js 里實現了一個簡單的模塊加載器,本文簡單介紹一下加載器的實現。

因為 JS 本身沒有模塊加載的概念,隨著前端的發展,各種加載技術也發展了起來,早期的seajs,requirejs,現在的 webpack,Node.js等等,模塊加載器的背景是代碼的模塊化,因為我們不可能把所有代碼寫到同一個文件,所以模塊加載器主要是解決模塊中加載其他模塊的問題,不僅是前端語言,c語言、python、php同樣也是這樣。No.js 參考的是 Node.js的實現。比如我們有以下兩個模塊。module1.js

  1. const func = require("module2");func(); 

module2.js

  1. module.exports = () => { 
  2.     // some code 
  3.  

我們看看如何實現模塊加載的功能。首先看看運行時執行的時候,是如何加載第一個模塊的。No.js 在初始化時會通過 V8 執行 No.js文件。

  1. const { 
  2.     loader, 
  3.     process, 
  4.  
  5. } = No
  6.  
  7.  
  8.  
  9. function loaderNativeModule() { 
  10.     // 原生 JS模塊列表 
  11.     const modules = [ 
  12.         { 
  13.             module: 'libs/module/index.js'
  14.             name'module' 
  15.         }, 
  16.     ]; 
  17.     No.libs = {}; 
  18.     // 初始化 
  19.     for (let i = 0; i < modules.length; i++) { 
  20.         const module = { 
  21.             exports: {}, 
  22.         }; 
  23.         loader.compile(modules[i].module).call(null, loader.compile, module.exports, module); 
  24.         No.libs[modules[i].name] = module.exports; 
  25.  
  26.         } 
  27.  
  28.  
  29.  
  30. function runMain() { 
  31.     No.libs.module.load(process.argv[1]); 
  32.  
  33.  
  34. loaderNativeModule();runMain(); 

No.js文件的邏輯主要是兩個,加載原生 JS 模塊和執行用戶的 JS。首先來看一下如何加載原生JS模塊,模塊加載是通過loader.compile實現的,loader.compile是 V8 函數的封裝。

  1. void No::Loader::Compile(V8_ARGS) { 
  2.     V8_ISOLATE 
  3.     V8_CONTEXT 
  4.     String::Utf8Value filename(isolate, args[0].As<String>()); 
  5.     int fd = open(*filename, 0 , O_RDONLY); 
  6.     std::string content; 
  7.     char buffer[4096]; 
  8.     while (1) 
  9.     { 
  10.       memset(buffer, 0, 4096); 
  11.       int ret = read(fd, buffer, 4096); 
  12.       if (ret == -1) { 
  13.         return args.GetReturnValue().Set(newStringToLcal(isolate, "read file error")); 
  14.       } 
  15.       if (ret == 0) { 
  16.         break; 
  17.       } 
  18.       content.append(buffer, ret); 
  19.     } 
  20.     close(fd); 
  21.     ScriptCompiler::Source script_source(newStringToLcal(isolate, content.c_str())); 
  22.     Local<String> params[] = { 
  23.       newStringToLcal(isolate, "require"), 
  24.       newStringToLcal(isolate, "exports"), 
  25.       newStringToLcal(isolate, "module"), 
  26.     }; 
  27.     MaybeLocal<Function> fun = 
  28.     ScriptCompiler::CompileFunctionInContext(context, &script_source, 3, params, 0, nullptr); 
  29.     if (fun.IsEmpty()) { 
  30.       args.GetReturnValue().Set(Undefined(isolate)); 
  31.     } else { 
  32.       args.GetReturnValue().Set(fun.ToLocalChecked()); 
  33.     } 
  34.  

Compile首先讀取模塊的內容,然后調用CompileFunctionInContext函數。CompileFunctionInContext函數的原理如下。假設文件內容是 1 + 1。執行以下代碼后

  1. const ret = CompileFunctionInContext("1+1", ["require""exports""module"]) 

ret變成

  1. function (require, exports, module) { 
  2.     1 + 1; 
  3.  

所以CompileFunctionInContext的作用是把代碼封裝到一個函數中,并且可以設置該函數的形參列表。回到原生 JS 的加載過程。

  1. for (let i = 0; i < modules.length; i++) { 
  2.         const module = { 
  3.             exports: {}, 
  4.         }; 
  5.         loader.compile(modules[i].module).call(null, loader.compile, module.exports, module); 
  6.         No.libs[modules[i].name] = module.exports;      

首先通過loader.compile和模塊內容得到一個函數,然后傳入參數執行該函數。我們看看原生JS 模塊的代碼。

  1. class Module { 
  2.     // ... 
  3.  
  4. }; 
  5.  
  6.  
  7. module.exports = Module; 

最后導出了一個Module函數并記錄到全局變量 No中。原生模塊就加載完畢了,接著執行用戶 JS。

  1. function runMain() { 
  2.     No.libs.module.load(process.argv[1]); 
  3.  

我們看看No.libs.module.load。

  1. static load(filename, ...args) { 
  2.     if (map[filename]) { 
  3.         return map[filename]; 
  4.     } 
  5.     const module = new Module(filename, ...args); 
  6.     return (map[filename] = module.load()); 
  7.  

新建一個Module對象,然后執行他的load函數。

  1. load() { 
  2.     const result = loader.compile(this.filename); 
  3.     result.call(this, Module.load, this.exports, this); 
  4.     return this.exports; 
  5.  

load函數最終調用loader.compile拿到一個函數,最后傳入三個參數執行該函數,就可以通過module.exports拿到模塊的導出內容。從中我們也看到,模塊里的require、module和exports到底是哪里來的,內容是什么。

 

責任編輯:姜華 來源: 編程雜技
相關推薦

2021-04-08 11:00:56

CountDownLaJava進階開發

2022-01-14 11:45:40

JVM 虛擬機Java

2021-04-06 10:19:36

Go語言基礎技術

2021-07-12 06:11:14

SkyWalking 儀表板UI篇

2022-08-19 06:40:02

V8GC

2021-08-25 06:33:52

Node.jsVscode調試工具

2022-03-20 06:40:31

Node.jsperf_hooks性能數據

2022-02-25 15:50:05

OpenHarmonToggle組件鴻蒙

2021-10-28 08:51:53

GPIO軟件框架 Linux

2023-03-13 09:31:04

2021-07-08 07:30:13

Webpack 前端Tree shakin

2021-05-08 08:36:40

ObjectString前端

2021-04-23 08:59:35

ClickHouse集群搭建數據庫

2021-04-14 07:55:45

Swift 協議Protocol

2021-06-21 14:36:46

Vite 前端工程化工具

2021-01-28 08:55:48

Elasticsear數據庫數據存儲

2023-03-29 07:45:58

VS編輯區編程工具

2021-04-14 14:16:58

HttpHttp協議網絡協議

2021-07-21 09:48:20

etcd-wal模塊解析數據庫

2024-06-13 08:34:48

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 毛片区| 亚洲一区在线日韩在线深爱 | 亚洲免费一区 | 99精品久久 | www.婷婷亚洲基地 | 91麻豆蜜桃一区二区三区 | 国产精品欧美一区二区三区 | 国产91九色 | www日本在线观看 | 不用播放器看的av | 国产精品久久久久久久模特 | 亚洲精品中文字幕中文字幕 | 成年男女免费视频网站 | 美女天天操| 黄色一级片在线播放 | 黄色一级视频 | 精品视频一区二区三区在线观看 | 3级毛片| 久久久日韩精品一区二区三区 | 欧美一区二区大片 | 日韩在线精品强乱中文字幕 | 成人精品久久 | 精品三区 | 精品久久久久久久久久久久 | 欧美日韩国产不卡 | 日本特黄a级高清免费大片 成年人黄色小视频 | 亚洲国产精品久久久久久 | 中文字幕精品一区久久久久 | 国产伦精品一区二区三区照片91 | 涩涩视频在线看 | 激情国产| 国产欧美精品区一区二区三区 | 亚洲在线一区二区 | 欧美一区二区三区视频在线 | 欧美一级视频在线观看 | 国内自拍偷拍一区 | 久久精品国产一区老色匹 | 亚洲视频一| 中文字幕日韩欧美一区二区三区 | 久久久久久99 | 一级毛片视频在线观看 |