整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          require.js 禁用緩存

          require.js 禁用緩存

          每次發版用戶都要清除頁面緩存

          • Require.js 模塊緩存:Require.js 內部有一個簡單的模塊緩存機制。當通過 require 加載模塊時,Require.js 會檢查該模塊是否已經緩存。如果已經緩存,Require.js 將直接返回緩存的模塊,而不會再次加載。這樣可以避免重復加載相同的模塊,提高性能。

          有時候我們禁用緩存,以便及時看到最新的修改。在這種情況下,可以通過給 Require.js 的配置對象添加一個隨機的查詢參數來防止緩存。例如:

          require.config({
           urlArgs: "bust=" + (new Date()).getTime()
          });
          
          require(["module"], function(module) {
            // 模塊邏輯
          });

          這會在每次加載模塊時,給腳本的 URL 添加一個不同的時間戳參數,迫使瀏覽器重新下載和執行模塊文件,以確保獲取最新的代碼。

          加時間戳禁用緩存在生產環境中不建議使用,因為它會增加頁面加載時間。只在開發過程中使用禁用緩存來方便調試和測試。

          我們可以在生產環境中加個固定的版本號

          、require 是一個函數,同時還掛載著四個屬性

          • require.resolve 解析某個文件是否存在,存在就返回此文件的絕對路徑,否則會報錯
          • require.main 當前所在文件的模塊信息
          • require.extensions 對象存放著能解析的文件類型,有 .js、.json、.node 三種類型
          • require.cache 對象存放著已經緩存的模塊(一個文件絕對路徑為鍵名,記載著這個文件的信息)

          2、require 函數的參數說明

          • 只有一個參數
          • 參數類型都是字符串
          • 參數可以是:
          • 模塊(原生內置fs/http/path/https等、第三方包模塊express、koa等等)
          • 路徑+文件基礎名(./express 當前路徑、../express 上級路徑、/express 絕對路徑)
          • 路徑+文件基礎名+文件擴展名(./express.js 當前路徑、../express.json 上級路徑、/express.node 絕對路徑)

          3、reqiure 調用的時候

          - 如果引用的是 .js 文件
            - fs模塊同步讀取文件
            - 包裝fs模塊同步讀取的內容
            - 調用 vm 的 runInThisContext 方法 將 包裝字符串 解析為 javascript
            - 調用匿名函數,并傳參,最后返回 module.exports 的賦值。
          
          - 如果引用的是 .json 文件
            - 經過fs模塊同步讀取文件以后用 JSON.parse() 解析返回結果。
          
          - 如果引用的是 .node 文件
            - 則經過 dlopen()方法加載最后編譯生成的對象,并且返回結果。

          4、require 加載規則

          加載規則參考地址:

           https://www.jianshu.com/p/a309864c8357
           https://blog.csdn.net/u010476739/article/details/80925128
           https://www.cnblogs.com/zhoulixue/p/8757546.html
           http://www.javashuo.com/article/p-bywkbpzj-d.html
           https://juejin.cn/post/6844903704123211783

          加載的模塊類型:

           1、原生內置模塊
               存在:原生內置模塊緩沖區中,直接返回緩存結果,不執行原生內置模塊代碼
               不存在:原生內置模塊緩沖區中,執行原生內置模塊代碼,把模塊加入緩沖區,并返回執行結果
           2、路徑文件模塊
           
               (1)、構建文件絕對路徑列表
                   存在后綴名(.js | .json | .node)
                       使用path.resolve("路徑") 拼接一個絕對路徑,推入文件絕對路徑列表
                   不存在后綴名
                       使用 path.resolve("路徑"+".js") 拼接一個絕對路徑的 .js 文件,推入文件絕對路徑列表
                       使用 path.resolve("路徑"+".json") 拼接一個絕對路徑的 .json 文件,推入文件絕對路徑列表
                       使用 path.resolve("路徑"+".node") 拼接一個絕對路徑的 .node 文件,推入文件絕對路徑列表
                       是否存在 path.resolve("路徑") 目錄
                           存在
                               是否存在package.json文件
                                   存在
                                       是否存在main屬性(若main沒指定后綴名,那會使用 .js | .json | .node,按照順序查找)
                                           存在
                                               使用path.resolve(path.jon("路徑",'main屬性值')) 拼接一個絕對路徑的文件,推入 文件絕對路徑列表
                                           不存在
                                               使用path.resolve(path.jon("路徑",'index.js')) 拼接一個絕對路徑的 .js 文件,推入 文件絕對路徑列表
                                               使用path.resolve(path.jon("路徑",'index.json')) 拼接一個絕對路徑的 .json 文件,推入 文件絕對路徑列表
                                               使用path.resolve(path.jon("路徑",'index.node')) 拼接一個絕對路徑的 .node 文件,推入 文件絕對路徑列表
                                   不存在
                                       使用path.resolve(path.jon("路徑",'index.js')) 拼接一個絕對路徑的 .js 文件,推入 文件絕對路徑列表
                                       使用path.resolve(path.jon("路徑",'index.json')) 拼接一個絕對路徑的 .json 文件,推入 文件絕對路徑列表
                                       使用path.resolve(path.jon("路徑",'index.node')) 拼接一個絕對路徑的 .node 文件,推入 文件絕對路徑列表
           
               (2)、遍歷文件絕對路徑列表 ,查看是否在require.cache['文件路徑']緩沖區中
                   存在
                       讀取緩沖區中的模塊,不執行文件模塊的代碼,直接返回緩存的結果(require.cache['文件路徑'].exports)
                   不存在
                       報錯找不到模塊


           3、第三方包模塊
           
               (1)、獲取模塊可能存在的目錄列表 module.paths 
           
               (2)、構建 文件絕對路徑列表
           
                   遍歷 目錄列表 module.paths 第一個元素
                       使用(path.join(目錄元素,包名+".js") 拼接一個絕對路徑的 .js 文件,推入 文件絕對路徑列表
                       使用(path.join(目錄元素,包名+".json") 拼接一個絕對路徑的 .json 文件,推入 文件絕對路徑列表
                       使用(path.join(目錄元素,包名+".node") 拼接一個絕對路徑的 .node 文件,推入 文件絕對路徑列表
                       判斷 path.join(目錄元素,包名) 目錄是否存
                           存在
                               判斷目錄下是否存在package.json文件
                                   存在
                                       是否存在main屬性
                                           存在
                                               使用 path.jon(目錄元素",包名,'main屬性值')) 拼接一個絕對路徑的文件,推入 文件絕對路徑列表
                                           不存在
                                               使用 path.jon(目錄元素",包名,'index.js')) 拼接一個絕對路徑的文件,推入 文件絕對路徑列表
                                               使用 path.jon(目錄元素",包名,'index.json')) 拼接一個絕對路徑的文件,推入 文件絕對路徑列表
                                               使用 path.jon(目錄元素",包名,'index.node)) 拼接一個絕對路徑的文件,推入 文件絕對路徑列表
                                   不存在
                                       繼續遍歷 目錄列表 module.paths
                           不存在
                               繼續遍歷 目錄列表 module.paths
           
               (3)、遍歷文件絕對路徑列表,查看是否在require.cache['文件路徑']緩沖區中
                   存在
                       讀取緩沖區中的模塊,不執行文件模塊的代碼,直接返回緩存的結果(require.cache['文件路徑'].exports)
                   不存在
                       報錯找不到模塊


          5、require 3種文件的加載方式

          謝 @曉之車 在我上一篇分享(模塊化中的import與require及區別)中的提問,我也特定研究了一番,這里是一篇很早的博文,一起來看下作者的分析

          Node.js也使用了CommonJS模塊機制,最近在InfoQ上有一篇文章討論了這方面的問題。這篇文章提到Node.js在載入模塊時,如果之前該模塊已經加載過則不會有重復開銷,因為模塊加載有緩存機制。這篇文章是我初審的,當時也正好在思考Jscex在Node.js使用時的模塊化問題,但研究了它的規則之后,我發現在某些情況下還是可能加載多次。現在我們便來分析這個問題。

          當我們使用require方法加載另一模塊的時候,Node.js會去查詢一系列的目錄。我們可以從module.paths中得到這些路徑,例如:

          [ '/Users/jeffz/Projects/node-test/node_modules',
            '/Users/jeffz/Projects/node_modules',
            '/Users/jeffz/node_modules',
            '/Users/node_modules',
            '/node_modules']

          這里是我在運行/User/jeffz/Projects/node-test目錄下一個模塊時得到的結果。可見,Node.js會從當前模塊所在目錄的node_modules(這里怎么不遵守Unix習慣,而使用了下劃線呢?)開始找起,如果沒找到再會去找上級目錄的node_modules,直到根目錄為止。當然,實際情況下還會有NODE_PATH環境變量標識的目錄等等。當模塊的位置確定之后,Node.js便會查看這個位置的模塊是否已經被加載,如果已加載,則直接返回。

          簡單地說,Node.js是根據模塊所在路徑來緩存模塊的。

          這么看來,“相同模塊是否會被加載多次”這個問題,其實就演變成了“相同模塊是否會出現在不同路徑里”。簡單想來這似乎不太可能,因為如果我們要使用某個模塊的時候,它的位置總是確定的。例如,使用npm安裝的模塊,總是會出現在當前目錄的node_modules里,加載時總是會找到相同的路徑。那么,在“間接”依賴相同模塊的情況下呢?

          例如我們想要使用Express框架,于是使用npm來安裝,便會得到:

          $ npm install express
          express@2.5.2 ./node_modules/express 
          ├── mkdirp@0.0.7
          ├── qs@0.4.0
          ├── mime@1.2.4
          └── connect@1.8.5

          可見,Express依賴了其他一些模塊,它們都存放在express模塊自己的目錄里面,例如./node_modules/express/node_modules/mime。好,假如我們項目自身也要使用mime項目,我們自然也可以使用npm來安裝:

          $ npm install mime
          mime@1.2.4 ./node_modules/mime 

          于是我們最終得到的是這樣的結構:

          ./node_modules
          ├── mime
          └── express
              └── node_modules
                  ├── mkdirp
                  ├── qs
                  ├── mime
                  └── connect

          請注意,這里的mime模塊便出現在兩個位置上,它們名稱版本都一致,完全是一個模塊。那么試想,如果我們在自己的代碼里加載的mime模塊,以及express內部加載的mime模塊是同一個嗎?顯然不是,可見,在這里相同的模塊被重復加載了兩次,產生了兩個模塊“實例”。

          這種重復加載在一般情況下不會有太大問題,最多內存占用大一點而已,不會影響程序的正確性。但是,我們也可以輕易設想到一些意外的情況。例如,在Jscex中,每個Task對象我都會給定一個ID,不斷增長。要實現這點我們需要維護一個“種子”,全局唯一。之前這個種子定義在閉包內部,但由于Jscex模塊會被加載多次,這樣從不同模塊“實例”生成的Task對象,它們的ID便有可能重復。當然,解決這個問題也并不困難,只需要將種子定義在根對象上即可,不同的模塊“實例”共享相同的根對象。

          還有個問題可能就顯得隱蔽些了,我們可以通過一個簡單的實驗來觀察結果。我們先來定義一個jeffz-a模塊,其中暴露出一個MyType類型:

          module.exports.MyType=function () { }

          然后將其發布到npm上。然后再寫一個jeffz-b模塊,依賴jeffz-a,并將jeffz-a中定義的MyType類型直接暴露出去:

          module.exports.MyType=require("jeffz-a").MyType;

          接著將jeffz-b也發布置npm上。再重新寫一個測試模塊,使用npm安裝jeffz-a和jeffz-b,最終目錄會是這樣的:

          ./node_modules
          ├── jeffz-a
          └── jeffz-b
              └── node_modules
                  └── jeffz-a

          在測試模塊內,我們來測試實例與類型之間的關系:

          var a=require("jeffz-a");
          var b=require("jeffz-b");
          
          console.log(new a.MyType() instanceof a.MyType); // true
          console.log(new b.MyType() instanceof b.MyType); // true
          
          console.log(new a.MyType() instanceof b.MyType); // false
          console.log(new b.MyType() instanceof a.MyType); // false

          從表面上看,jeffz-b和jeffz-a暴露出的應該是相同的MyType類型,它們的對象通過instanceof相互判斷應該都返回true,但實際上由于jeffz-b中的jeffz-a,與我們直接加載的jeffz-a模塊是不同的實例,因此MyType類型自然也不是同一個了。

          這對于Jscex的影響在于,Jscex的異步模塊在取消時,原本是通過判斷異常對象是否為CanceledError類型來決定Task的狀態為cancelled還是faulted。但由于Node.js可能會將相同的模塊加載為多個實例,因此即便拋出的的確是某個實例的CancelledError,也無法通過另一個實例內部的判斷。因此,目前Jscex的判斷方式修改為檢查異常對象的isCancellation字段,簡單地解決了這個問題。

          當然,Node.js這種“重復加載”的影響也并非完全是負面的,至少它天然的解決了多版本共存的問題。例如,express v2.5.2依賴mime v1.2.4,但我們程序自身又想使用mime v1.2.5。此時,express內部自然使用mime v1.2.4,而我們自己的程序使用的便是mime v1.2.5。

          有些情況下您可能也想避免這種重復加載,這就必須手動地刪除模塊內部被間接依賴的模塊,將其移動到模塊查詢路徑的公用部分上了。就目前看來,這些操作必須手動進行,因為npm在安裝模塊時不會關心依賴的模塊是否已經安裝過了(例如在NODE_PATH環境變量標識的路徑里),它一定會重新下載所有依賴的模塊。可惜如果您使用的是托管形式的Node.js服務,則很有可能無法做到這一點。

          原文地址:Node.js中相同模塊是否會被加載多次?-CSDN博客


          主站蜘蛛池模板: 91无码人妻精品一区二区三区L| 红桃AV一区二区三区在线无码AV| 亚洲一区二区三区写真| 在线观看精品一区| 蜜桃传媒一区二区亚洲AV| 综合一区自拍亚洲综合图区| 色系一区二区三区四区五区 | 国产精品 一区 在线| 亚洲国产精品一区二区九九| 国产伦精品一区二区三区免费迷 | 一区二区三区视频在线观看| 78成人精品电影在线播放日韩精品电影一区亚洲| 中文字幕日韩一区二区三区不| 日本一区二区三区免费高清在线 | 无码国产精品一区二区免费I6| 国产裸体舞一区二区三区| 麻豆va一区二区三区久久浪| 日本一区二区三区免费高清在线| 久久精品一区二区| 久久久无码一区二区三区| 国模极品一区二区三区| 好爽毛片一区二区三区四无码三飞| 日本一区二区三区不卡视频中文字幕| 激情内射亚州一区二区三区爱妻| 少妇无码一区二区三区| 精品久久久久久无码中文字幕一区 | 精品欧美一区二区在线观看 | 无码囯产精品一区二区免费| 亚洲一区二区三区国产精华液| 婷婷国产成人精品一区二 | 久久综合精品不卡一区二区| 91福利一区二区| 日韩动漫av在线播放一区| 性色AV一区二区三区| 天天躁日日躁狠狠躁一区| 国产一区二区高清在线播放| 国产福利91精品一区二区 | 人妻AV中文字幕一区二区三区 | 精品福利视频一区二区三区| 日韩毛片一区视频免费| 97久久精品无码一区二区天美|