緩存熱更新
1. Lol腳本是什麼意思
通常說的腳本其實就是半個外掛程序。可以將其理解為輔助工具。
腳本(Script)是一種批處理文件的延伸,是一種純文本保存的程序,一般來說的計算機腳本程序是確定的一系列控制計算機進行運算操作動作的組合,在其中可以實現一定的邏輯分支等。
腳本簡單地說就是一條條的文字命令,這些文字命令是可以看到的(如可以用記事本打開查看、編輯),腳本程序在執行時,是由系統的一個解釋器,將其一條條的翻譯成機器可識別的指令,並按程序順序執行。因為腳本在執行時多了一道翻譯的過程,所以它比二進製程序執行效率要稍低一些。
(1)緩存熱更新擴展閱讀:
腳本執行:
腳本通常可以由應用程序臨時調用並執行。各類腳本被廣泛地應用於網頁設計中,因為腳本不僅可以減小網頁的規模和提高網頁瀏覽速度,而且可以豐富網頁的表現,如動畫、聲音等。舉個最常見的例子,當點擊網頁上的Email地址時能自動調用Outlook Express或Foxmail這類郵箱軟體,就是通過腳本功能來實現的。
也正因為腳本的這些特點,往往被一些別有用心的人所利用。例如在腳本中加入一些破壞計算機系統的命令,這樣當用戶瀏覽網頁時,一旦調用這類腳本,便會使用戶的系統受到攻擊。
所以用戶應根據對所訪問網頁的信任程度選擇安全等級,特別是對於那些本身內容就非法的網頁,更不要輕易允許使用腳本。通過「安全設置」對話框,選擇「腳本」選項下的各種設置就可以輕松實現對腳本的禁用和啟用。
2. webstorm怎麼設置熱更新
hot: true,
在配置中配置了熱更新,但是頁面就是刷新不了
bug環境:webstorm 2017.2.2 webpact2.x
有可能是webstorm中設置了ide緩存
把
use "safe write" (save changes to temporary file first)
選項勾去除
3. 熱更新真的那麼重要嗎
背景 相信使用 Node.js 過 Web 應用的同學一定苦惱過新修改的代碼必須要重啟 Node.js 進程後才能更新的問題。習慣使用 PHP 的同學更會非常的不適用,大呼果然還是我大PHP才是世界上最好的編程語言。手動重啟進程不僅僅是非常惱人的重復勞動,當應用規模稍大以後,啟動時間也逐漸開始不容忽視。 當然作為程序猿,無論使用哪種語言,都不會讓這樣的事情折磨自己。解決這類問題最直接和普適的手段就是監聽文件修改並重啟進程。這個方法也已經有很多成熟的解決方案提供了,比如已經被棄坑的 node-supervisor,以及現在比較火的 PM2 ,或者比較輕量級的 node-dev 等等均是這樣的思路。 本文則提供了另外一種思路,只需要很小的改造,就可以實現真正的0重啟熱更新代碼,解決 Node.js Web 應用時惱人的代碼更新問題。 總體思路 說起代碼熱更新,當下最有名的當屬 Erlang 語言的熱更新功能,這門語言的特色在於高並發和分布式編程,主要的應用場景則是類似證券交易、游戲服務端等領域。這些場景都或多或少要求服務擁有在運行中運維的手段,而代碼熱更新就是其中非常重要的一環,因此我們可以先簡單的了解一下 Erlang 的做法。 由於我也沒有使用過 Erlang ,以下內容均為道聽途說,如果希望深入和准確的了解 Erlang 的代碼熱更新實現,最好還是查閱官方文檔。 Erlang 的代碼載入由一個名為code_server的模塊管理,除了啟動時的一些必要代碼外,大部分的代碼均是由code_server載入。 當code_server發現模塊代碼被更新後,會重新載入模塊,此後的新請求會使用新模塊執行,而原有還在執行的請求則繼續使用老模塊執行。 老模塊會在新模塊載入後,被打上old標簽,新模塊則是current標簽。當下一次熱更新的時候,Erlang 會掃描還在執行老模塊的進行並殺掉,再繼續按照這個邏輯更新模塊。 Erlang 中並非所有代碼均允許熱更新,如 kernel, stdlib, compiler 等基礎模塊默認是不允許更新的 我們可以發現 Node.js 中也有與code_server類似的模塊,即 reuire 體系,因此 Erlang 的做法應該也可以在 Node.js 上做一些嘗試。通過了解 Erlang 的做法,我們可以大概的總結出在 Node.js 中解決代碼熱更新的關鍵問題點 如何更新模塊代碼 如何使用新模塊處理請求 如何釋放老模塊的資源 那麼接下來我們就逐個的解析這些問題點。 如何更新模塊代碼 要解決模塊代碼更新的問題,我們就需要去閱讀 Node.js 的模塊管理器實現,直接上鏈接 mole.js。通過簡單的閱讀,我們可以發現核心的代碼就在於 Mole._load ,稍微精簡一下代碼貼出來。 // Check the cache for the reuested file. // 1. If a mole already exists in the cache: return its exports object. // 2. If the mole is native: call `NativeMole.reuire()` with the // filename and return the result. // 3. Otherwise, create a new mole for the file and save it to the cache. // Then have it load the file contents before returning its exports // object. Mole._load = function(reuest, parent, isMain) { var filename = Mole._resolveFilename(reuest, parent); var cachedMole = Mole._cache[filename]; if (cachedMole) { return cachedMole.exports; } var mole = new Mole(filename, parent); Mole._cache[filename] = mole; mole.load(filename); return mole.exports; }; reuire.cache = Mole._cache; 可以發現其中的核心就是 Mole._cache ,只要清除了這個模塊緩存,下一次 reuire 的時候,模塊管理器就會重新載入最新的代碼了。 寫一個小程序驗證一下 // in.js function cleanCache (mole) { var path = reuire.resolve(mole); reuire.cache[path] = null; } setInterval(function () { cleanCache('./code.js'); var code = reuire('./code.js'); console.log(code); }, ); // code.js mole.exports = 'hello world'; 我們執行一下 in.js ,同時取修改 code.js 的內容,就可以發現控制台中,我們代碼成功的更新為了最新的代碼。 那麼模塊管理器更新代碼的問題已經解決了,接下來再看看在 Web 應用中,我們如何讓新的模塊可以被實際執行。 如何使用新模塊處理請求 為了更符合大家的使用習慣,我們就直接以 Express 為例來展開這個問題,實際上使用類似的思路,絕大部分 Web應用 均可適用。 首先,如果我們的服務是像 Express 的 DEMO 一樣所有的代碼均在同一模塊內的話,我們是無法針對模塊進行熱載入的 var express = reuire('express'); var app = express(); app.get('/', function(re, res){ res.send('hello world'); }); app.listen(); 要實現熱載入,和 Erlang 中不允許的基礎庫一樣,我們需要一些無法進行熱更新的基礎代碼控制更新流程。而且類似 app.listen 這類操作如果重新執行了,那麼和重啟 Node.js 進程也沒太大的區別了。因此我們需要一些巧妙的代碼將頻繁更新的業務代碼與不頻繁更新的基礎代碼隔離開。 // app.js 基礎代碼 var express = reuire('express'); var app = express(); var router = reuire('./router.js'); app.use(router); app.listen(); // router.js 業務代碼 var express = reuire('express'); var router = express .Router(); // 此處載入的中間件也可以自動更新 router.use(express.static('public')); router.get('/', function(re, res){ res.send('hello world'); }); mole.exports = router; 然而很遺憾,經過這樣處理之後,雖然成功的分離了核心代碼, router.js 依然無法進行熱更新。首先,由於缺乏對更新的觸發機制,服務無法知道應該何時去更新模塊。其次, app.use 操作會一直保存老的 router.js 模塊,因此即使模塊被更新了,請求依然會使用老模塊處理而非新模塊。 那麼繼續改進一下,我們需要對 app.js 稍作調整,啟動文件監聽作為觸發機制,並且通過閉包來解決 app.use 的緩存問題 // app.js var express = reuire('express'); var fs = reuire('fs'); var app = express(); var router = reuire('./router.js'); app.use(function (re, res, next) { // 利用閉包的特性獲取最新的router對象,避免app.use緩存router對象 router(re, res, next); }); app.listen(); // 監聽文件修改重新載入代碼 fs.watch(reuire.resolve('./router.js'), function () { cleanCache(reuire.resolve('./router.js')); try { router = reuire('./router.js'); } catch (ex) { console.error('mole update failed'); } }); function cleanCache(molePath) { reuire.cache[molePath] = null; } 再試著修改一下 router.js 就會發現我們的代碼熱更新已經初具雛形了,新的請求會使用最新的 router.js 代碼。除了修改 router.js 的返回內容外,還可以試試看修改路由功能,也會如預期一樣進行更新。 當然,要實現一個完善的熱更新方案需要更多結合自身方案做一些改進。首先,在中間件的使用上,我們可以在 app.use 處聲明一些不需要熱更新或者說每次更新不希望重復執行的中間件,而在 router.use 處則可以聲明一些希望可以靈活修改的中間件。其次,文件監聽不能僅監聽路由文件,而是要監聽所有需要熱更新的文件。除了文件監聽這種手段外,還可以結合編輯器的擴展功能,在保存時向 Node.js 進程發送或者訪問一個特定的 URL 等方式來觸發更新。 如何釋放老模塊的資源 要解釋清楚老模塊的資源如何釋放的問題,實際上需要先了解 Node.js 的內存回收機制,本文中並不準備詳加描述,解釋 Node.js 的內存回收機制的文章和書籍很多,感興趣的同學可以自行擴展閱讀。簡單的總結一下就是當一個對象沒有被任何對象引用的時候,這個對象就會被標記為可回收,並會在下一次GC處理的時候釋放內存。 那麼我們的課題就是,如何讓老模塊的代碼更新後,確保沒有對象保持了模塊的引用。首先我們以 如何更新模塊代碼 一節中的代碼為例,看看老模塊資源不回收會出現什麼問題。為了讓結果更顯著,我們修改一下 code.js // code.js var array = []; for (var i = 0; i < ; i++) { array.push('mem_leak_when_reuire_cache_clean_test_item_' + i); } mole.exports = array; // app.js function cleanCache (mole) { var path = reuire.resolve(mole); reuire.cache[path] = null; } setInterval(function () { var code = reuire('./code.js'); cleanCache('./code.js'); }, 10); 好~我們用了一個非常笨拙但是有效的方法,提高了 router.js 模塊的內存佔用,那麼再次啟動 in.js 後,就會發現內存出現顯著的飆升,不到一會 Node.js 就提示 process out of memory。然而實際上從 app.js 與 router.js 的代碼中觀察的話,我們並沒發現哪裡保存了舊模塊的引用。 我們藉助一些 profile 工具如 node-heapmp 就可以很快的定位到問題所在,在 mole.js 中我們發現 Node.js 會自動為所有模塊添加一個引用 function Mole(id, parent) { this.id = id; this.exports = {}; this.parent = parent; if (parent && parent.children) { parent.children.push(this); } this.filename = null; this.loaded = false; this.children = []; } 因此相應的,我們可以調整一下cleanCache函數,將這個引用在模塊更新的時候一並去除。 // app.js function cleanCache(molePath) { var mole = reuire.cache[molePath]; // remove reference in mole.parent if (mole.parent) { mole.parent.children.splice(mole.parent.children.indexOf(mole), 1); } reuire.cache[molePath] = null; } setInterval(function () { var code = reuire('./code.js'); cleanCache(reuire.resolve('./code.js')); }, 10); 再執行一下,這次好多了,內存只會有輕微的增長,說明老模塊佔用的資源已經正確的釋放掉了。 使用了新的 cleanCache 函數後,常規的使用就沒有問題,然而並非就可以高枕無憂了。在 Node.js 中,除了 reuire 系統會添加引用外,通過 EventEmitter 進行事件監聽也是大家常用的功能,並且 EventEmitter 有非常大的嫌疑會出現模塊間的互相引用。那麼 EventEmitter 能否正確的釋放資源呢?答案是肯定的。 // code.js var moleA = reuire('events').EventEmitter(); moleA.on('whatever', function () { }); 當 code.js 模塊被更新,並且所有引用被移出後,只要 moleA 沒有被其他未釋放的模塊引用, moleA 也會被自動釋放,包括我們在其內部的事件監聽。 只有一種畸形的 EventEmitter 應用場景在這套體系下無法應對,即 code.js 每次執行的時候都會去監聽一個全局對象的事件,這樣會造成全局對象上不停的掛載事件,同時 Node.js 會很快的提示檢測到過多的事件綁定,疑似內存泄露。 至此,可以看到只要處理好了 reuire 系統中 Node.js 為我們自動添加的引用,老模塊的資源回收並不是大問題,雖然我們無法做到像 Erlang 一樣實現下一次熱更新對還留存的老模塊進行掃描這樣細粒度的控制,但是我們可以通過合理的規避手段,解決老模塊資源釋放的問題。 在 Web 應用下,還有一個引用問題就是未釋放的模塊或者核心模塊對需要熱更新的模塊有引用,如 app.use,導致老模塊的資源無法釋放,並且新的請求無確的使用新模塊進行處理。解決這個問題的手段就是控制全局變數或者引用的暴露的入口,在熱更新執行的過程中手動更新入口。如 如何使用新模塊處理請求 中對 router 的封裝就是一個例子,通過這一個入口的控制,我們在 router.js 中無論如何引用其他模塊,都會隨著入口的釋放而釋放。 另一個會引起資源釋放問題的就是類似 setInterval 這類操作,會保持對象的生命周期無法釋放,不過在 Web 應用中我們極少會使用這類技術,因此方案中並未關注。 尾聲 至此,我們就解決了 Node.js 在 Web 應用下代碼熱更新的三大問題,不過由於 Node.js 本身缺乏對有效的留存對象的掃描機制,因此並不能%的消除類似 setInterval 導致的老模塊的資源無法釋放的問題。也是由於這樣的局限性,目前我們提供的 YOG2 框架中,主要還是將此技術應用於調試期,通過熱更新實現快速。而生產環境的代碼更新依然使用重啟或者 PM2 的 hot reload 功能來保證線上服務的穩定性。 由於熱更新實際上與框架和業務架構緊密相關,因此本文並未給出一個通用的解決方案。作為參考,簡單的介紹一下在 YOG2 框架中我們是如何使用這項技術的。由於 YOG2 框架本身就支持前後端子系統 App 拆分,因此我們的更新策略是以 App 為粒度更新代碼。同時由於類似 fs.watch 這類操作會有兼容性問題,一些替代方案如 fs.watchFile 則會比較消耗性能,因此我們結合了 YOG2 的測試機部署功能,通過上傳部署新代碼的形式告知框架需要更新 App 代碼。在以 App 為粒度更新模塊緩存的同時,會更新路由緩存與模板緩存,來完成所有代碼的更新工作。 如果你使用的是類似 Express 或者 Koa 這類框架,只需要按照文中的方法結合自身業務需要,對主路由進行一些改造,就可以很好的應用這項技術。
4. APP上架版本直接熱更新的話,會不會存在緩存問題
APP熱更新,是指不通過蘋果APP Store版本更新審核,直接在應用自行的數據更新,在今年三月,蘋果已經警告過部分開發者違反了《蘋果開發者計劃許可協議》的3.3.2章節以及《App Store審查指南》2.5.2章節的規定,6月1日,部分開發者在iTC後台收到了一則通知:蘋果要求當前含有熱更新功能的App在6月12日前移除相關代碼,否則這些App可能會下架。
5. javascript能熱更新嗎
當然可以了,腳本都不需要重新啟動的。但是要刷新頁面,清理瀏覽器緩存。
1、實現原理
使用代理的方式讓所有類和實例能夠在js文件更改後, 對被代理對象進行替換, 實現熱更新.
2、作用
使用這個模塊引入的js文件, 在修改後不需要重啟伺服器, 可以達到下列效果:
1)require.cache更新了, 新的require使用新的js
2)原來舊的類對應的實例也更新了 具體就是: 綁定在prototype下的函數, 綁定在類上的函數等也更新了, 舊實例調用的是新的代碼.
3、注意
1)因為代理會消耗一定資源, 所以建議只在邏輯js上使用.
2)目前建議開發環境中用, 因為還在完善
4、安裝
npm install hot-require
5、引入
// app啟動時候引入這個模塊, 引入一次即可
require('hot-require');
6、示例
// 需要熱更新js, 用下面方式代替原有的require函數
var yourJs = _require(__dirname, '[your js path]');
6. 原生app嵌套h5頁面怎麼實現熱更新
這種方式必須要native另做一個同步功能了。若native開啟緩存,web靜態資源非覆蓋式發布,既能享受類似本地的快感,還能做到及時更新。
補充:
簡單做: 在靜態伺服器新建一個文本或json文件,裡面寫好版本號,版本號任意,你要更新的時候就去改這個版本號。native每次或定時去拉這個文件,並將版本號存在本地,以後拉取時比對本地版本號,有變化則重新拉取靜態資源到本地。
更好的是: 靜態文件打包時生成改動文件映射表,這個表只有已經改動的文件名稱或地址,native每次拉取這個映射表,發現有改動文件則只拉取改動文件。
這種方式必須要native另做一個同步功能了。若native開啟緩存,web靜態資源非覆蓋式發布,既能享受類似本地的快感,還能做到及時更新。