<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          只需幾行代碼,手寫實(shí)現(xiàn)【文件監(jiān)聽和自動(dòng)重啟】

          共 4953字,需瀏覽 10分鐘

           ·

          2021-09-15 22:55

          前言

          寫這篇文章的原因是因?yàn)?好奇于平時(shí) 在vscode或者其他編譯器寫代碼的時(shí)候,會(huì)在我修改代碼后重新打包,當(dāng)然我知道是webpack的功能,那它是怎么知道我修改了代碼的,我覺得肯定有個(gè)東西在監(jiān)聽,于是就研究了億下下。

          手寫實(shí)現(xiàn)

          稍微寫過一點(diǎn) node 應(yīng)用的同學(xué)應(yīng)該都有類似的經(jīng)歷,編寫一段代碼,運(yùn)行一個(gè) http server,保存為 js 文件,例如 app.js ,

          然后執(zhí)行命令

          node app.js

          此時(shí) node 就會(huì)執(zhí)行我們剛才書寫的代碼。此時(shí)一切看起來都很美好,但是隨著開發(fā)繼續(xù),一些問題也會(huì)逐漸顯現(xiàn)出來。

          每過一段時(shí)間,我們都想看下剛才書寫都代碼是否能夠正常運(yùn)行,那么每次保存代碼以后,我們都不得不 ctrl + C 結(jié)束掉剛才的 server,然后重新運(yùn)行這段腳本。于是乎一些能夠監(jiān)聽文件變化并支持自動(dòng)重啟的工具就出現(xiàn)在了我們的視線中。比如 hotnode,supervisor 等等。這些工具能夠很好的節(jié)約開發(fā)者在重復(fù)操作上花費(fèi)的時(shí)間,能夠把經(jīng)歷更加專注在其他方面。

          下面說一下如何實(shí)現(xiàn)一個(gè)極簡(jiǎn)的工具。

          文件監(jiān)聽

          fs.watch()

          fs,F(xiàn)ile System 的縮寫,利用這個(gè) API,我們可以對(duì)文件或者目錄進(jìn)行監(jiān)聽。當(dāng)監(jiān)聽到文件變化后,執(zhí)行預(yù)設(shè)的回調(diào)函數(shù)。

          fs.watch("app.js", (event, filename) => {
            // 文件變化時(shí)觸發(fā)的回調(diào)函、
          });

          細(xì)心的小伙伴可能已經(jīng)想到了,文件發(fā)生變化,我再去執(zhí)行一個(gè)什么函數(shù),把a(bǔ)pp.js再重新執(zhí)行一下,是不是就可以了?

          你說的沒錯(cuò)。

          自動(dòng)重啟

          API: child_process.spawn

          我們使用 spawn 開啟一個(gè)新的進(jìn)程,然后在在這個(gè)進(jìn)程中執(zhí)行 js 腳本即可,話不多說,上栗子:

          const { spawn } = require("child_process");
          let process = null;

          function startProcess({
            // 執(zhí)行js腳本
            process = spawn("node", ["app.js"]);

            // 打印輸出到控制臺(tái)
            process.stdout.on("data", data => {
              console.log(data.toString());
            });
          }

          // 有了start,還要有個(gè)restart
          function restartProcess({
            if (process !== null) {
              try {
                // 清除進(jìn)程,
                process.kill("SIGKILL");
              } catch (error) {
                console.log("Exception: " + error.message, "bad");
              }
            }

            // 然后這里再次啟動(dòng),可以說很像清除定時(shí)器的操作了~
            startProcess();
          }

          最后,我們把restartProcess放到fs.watch的回調(diào)函數(shù)里,再讓startProcess和fs.watch順序執(zhí)行就好了。像這樣:

          fs.watch("app.js", (event, filename) => {
            restartProcess();
          });

          startProcess();

          如果你想寫一個(gè)放心能用的工具,還是有很多東西要解決的,比如即使沒有修改文件內(nèi)容,單純的按下保存,也會(huì)觸發(fā) watch 函數(shù)的回調(diào)。這需要采取一定的策略去判斷保存前后文件內(nèi)容是否有變動(dòng)。

          有興趣的同學(xué)也可以去看下另一個(gè)庫(kù)的代碼,watch,鏈接:https://link.juejin.cn/?target=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2Fwatch

          相關(guān)優(yōu)化與思考

          這樣修改并保存的時(shí)候回發(fā)現(xiàn)一樣有點(diǎn)問題。直接保存,顯示兩次更新

          修改文件以后,一樣顯示兩次更新(mac系統(tǒng)上是兩次,其余系統(tǒng)可能有所差異)  這樣多是于操做系統(tǒng)對(duì)文件修改的事件支持有關(guān),在保存的時(shí)候出發(fā)了不止一次。

          下面聚焦于回調(diào)事件的參數(shù),event對(duì)應(yīng)事件類型,是否能夠判斷事件類型為change呢,才執(zhí)行呢,忽略空保存。

          fs.watch("app.js", (event, filename) => {
            if (filename && event == 'change') {
               restartProcess();
            }
            
          });

          startProcess();

          不過實(shí)際上,空的保存event也是change,另外不一樣平臺(tái)event的實(shí)現(xiàn)可能也有所不一樣。這種方式要pass掉。

          顯然從上面的例子能夠看到,變動(dòng)時(shí)間依然不可控。由于每次保存,node對(duì)應(yīng)stat對(duì)象依然會(huì)修改。

          對(duì)比文件內(nèi)容

          只能選擇這種方式來判斷是不是否更新。例如md5:

          const fs = require('fs'),
              md5 = require('md5');
          const filePath = './'    
          let preveMd5 = null

          fs.watch("app.js", (event, filename) => {
              var currentMd5 = md5(fs.readFileSync(filePath + filename))
              if (currentMd5 == preveMd5) {
                  return
              }
              preveMd5 = currentMd5
              restartProcess();
          });

          startProcess();

          沒錯(cuò),也可以說是判斷文件的hash值。

          先保存當(dāng)前文件md5值,每次文件變化時(shí)(即保存操做響應(yīng)以后),每次都獲取文件的md5而后進(jìn)行對(duì)比,看是否發(fā)生變化。

          不過這樣能夠看到,當(dāng)初次保存時(shí),都會(huì)執(zhí)行一次,由于初始值為null的緣故。這樣能夠加個(gè)兼容,根據(jù)是否第一次保存來判斷好了。

          對(duì)于不一樣的操做系統(tǒng),可能保存時(shí)觸發(fā)的回調(diào)不止一個(gè)(mac上到?jīng)]出現(xiàn))。為了不這種實(shí)時(shí)響應(yīng)對(duì)應(yīng)的頻繁觸發(fā),能夠引入debounce函數(shù)來保證性能。

          const fs = require('fs'),
              md5 = require('md5');
          let preveMd5 = null,
              fsWait = false
          const filePath = './'    
          fs.watch(filePath,(event,filename)=>{
              if (filename){
                  if (fsWait) return;
                  fsWait = setTimeout(() => {
                      fsWait = false;
                  }, 100)
                  var currentMd5 = md5(fs.readFileSync(filePath + filename))
                  if (currentMd5 == preveMd5){
                      return 
                  }
                  preveMd5 = currentMd5
                  restartProcess();
              }
          })

          startProcess();

          結(jié)束

          謝謝大家觀看。是不是忽然明白了文件是怎么被監(jiān)聽的了呢

           歡迎關(guān)注《前端陽(yáng)光》,加入技術(shù)交流群,加入內(nèi)推群


          相關(guān)文獻(xiàn)

          https://juejin.cn/post/6844903893785116680


          https://www.shangmayuan.com/a/07ce3c507d7a4c478e37f1f0.html




          瀏覽 49
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美激情成人网站 | 久久免费黄片视频 | 婷婷亚洲五月***久久 | 色中文娱乐 | 亚洲欧美日韩一级 |