предисловие
С быстрым развитием передовых технологий, передняя часть разработки также развилась от первоначальной косой черты к направлению инженерной эффективности. Помимо различных сред разработки, одна за другой появляются такие технологии, как упаковка и компиляция, а опыт разработки становится все лучше и лучше. HMR, например, делает наши обновления мгновенно видимыми, прощаясь с ручными F5. Реализация состоит в том, чтобы автоматически вызывать процесс сборки, отслеживая изменения файлов. Давайте сосредоточимся на том, как реализовать узел для отслеживания изменений файлов.
Сцены
Предположим, вы хотите прослушивать index.js и перекомпилировать каждый раз, когда содержимое изменяется.
Мы используем простую консоль для идентификации и выполнения компиляции. Следующее для достижения этой функции.
собственный API узла
fs.watchFile
Перелистните документацию узла, и вы увидите API, который соответствует нашим потребностям.fs.watchFile(ведь это файловая операция, скорее всего под модулем fs).
fs.watchFile(filename[, options], listener)
-
имя файла, очевидно, имя файла
-
необязательный объект options содержит следующие два свойства
- Продолжается ли процесс при отслеживании постоянного файла, значение по умолчанию — true.
- интервал, как долго обучать целевой файл, по умолчанию 5007 миллисекунд
-
Обратный вызов события прослушивателя содержит два параметра
- текущий объект статистики текущего файла
- объект статистики файла перед пред.
После прочтения информации о параметрах я не знаю, есть ли у вас какая-либо особая информация из атрибутов параметров. Особенно параметр интервала и параметр обратного вызова в слушателе.
Отслеживайте файл, соответствующий имени файла, и инициируйте обратный вызов при каждом доступе к файлу.
Здесь он будет срабатывать при каждом доступе к файлу, что фактически означает, что файл вводится снова после каждого переключения, а затем после сохранения обратный вызов будет запущен независимо от того, была ли произведена модификация.
Кроме того, можно ли угадать события опроса и файловые объекты.Принцип мониторинга заключается в том, чтобы опросить состояние файла в фиксированное время, а затем вернуть состояние до и после и дать оценку пользователю.
Поэтому node также рекомендует, чтобы, если вы хотите получить модификации файлов, вам нужно было сравнить по времени модификации объекта статистики, то есть сравнить curr.mtime и prev.mtime.
Это небольшая проблема, давайте сначала рассмотрим пример, так будет понятнее.
const fs = require('fs')
const filePath = './index.js'
console.log(`正在监听 ${filePath}`);
fs.watchFile(filePath, (cur, prv) => {
if (filePath) {
// 打印出修改时间
console.log(`cur.mtime>>${cur.mtime.toLocaleString()}`)
console.log(`prv.mtime>>${prv.mtime.toLocaleString()}`)
// 根据修改时间判断做下区分,以分辨是否更改
if (cur.mtime != prv.mtime){
console.log(`${filePath}文件发生更新`)
}
}
})
Тогда результаты теста следующие:
// 运行
node watch1.js
// 1、访问index.js 不做修改,然后保存
// 2、切换文件,再次访问,不做修改,只报错
// 3、编辑内容,并保存
Вы видите шаги 1 и 2, фактического изменения содержимого нет, но мы не можем их различить. Пока вы сохраняете после переключения, временная метка модификации mtime изменится.
Также время отклика очень медленное, в конце концов, это опрос.
По этим вопросам, собственно, официальный сайт и дал приговор:
Using fs.watch() is more efficient than fs.watchFile and fs.unwatchFile. fs.watch should be used instead of fs.watchFile and fs.unwatchFile when possible.
Не используйте watchFile, если вы можете использовать fs.watch. Во-первых, это эффективность, во-вторых, невозможно точно узнать статус модификации, а в-третьих, можно отслеживать только отдельные файлы.
Очевидно, что для фактического процесса разработки мы хотим сосредоточиться на изменениях в исходной папке.
fs.watch
Первое использование выглядит следующим образом:
fs.watch(filename[, options][, listener])
Похоже на fs.watchFile.
-
имя файла, очевидно, имя файла
-
необязательный объект или строка options содержит следующие три свойства
- Продолжается ли процесс при отслеживании постоянного файла, значение по умолчанию — true.
- Независимо от того, отслеживает ли рекурсивно все подкаталоги, значение по умолчанию false — это текущий каталог, а true — все подкаталоги.
- кодировка указывает имя файла, передаваемое в событие обратного вызова, по умолчанию используется utf8.
-
Обратный вызов события прослушивателя содержит два параметра
- тип события eventType, переименовать или изменить
- имя файла Имя файла текущего файла изменений
Если options является строкой, относящейся к кодировке.
Прослушивание файла или папки, соответствующей FileName (параметр Recursive также отражает эту функцию), возвращает объект FS.FSWATCHER.
Реализация этой функции основана на уведомлении базовой операционной системой об изменениях файла. Так что есть проблема, реализация разных платформ может быть не одинаковой. Пример 1 ниже:
const fs = require('fs')
const filePath = './'
console.log(`正在监听 ${filePath}`);
fs.watch(filePath,(event,filename)=>{
if (filename){
console.log(`${filename}文件发生更新`)
}
})
Отражено относительно очевидное преимущество: ответ более своевременный, а эффективность однозначно выше, чем у опроса.
Однако, когда я изменил и сохранил его таким образом, я обнаружил ту же проблему.
Сохранить напрямую, показывая два обновления
После модификации файла также отображаются два обновления (два раза в системе mac, в других системах может быть иначе)Это может быть связано с поддержкой события операционной системы для модификации файла, и оно запускалось не раз при сохранении.
Далее основное внимание уделяется параметрам события обратного вызова.Событие соответствует типу события.Можно ли судить, что тип события является изменением, а затем выполнить его, игнорируя пустое сохранение.
const fs = require('fs')
const filePath = './'
console.log(`正在监听 ${filePath}`);
fs.watch(filePath,(event,filename)=>{
console.log(`event类型${event}`)
if (filename && event == 'change') {
console.log(`${filename}文件发生更新`)
}
})
Но на самом деле пустое событие сохранения — это тоже изменение, и реализация событий на разных платформах тоже может быть разной. Этот способ пройти.
Проверить время смены
Очевидно из приведенного выше примера, что время изменения по-прежнему неуправляемо. Потому что каждый раз, когда вы сохраняете, объект статистики, соответствующий узлу, все равно будет изменен.
Сравните содержимое файла
Только этот способ можно выбрать, чтобы определить, обновлять или нет. Например мд5:
const fs = require('fs'),
md5 = require('md5');
const filePath = './'
let preveMd5 = null
console.log(`正在监听 ${filePath}`);
fs.watch(filePath,(event,filename)=>{
var currentMd5 = md5(fs.readFileSync(filePath + filename))
if (currentMd5 == preveMd5) {
return
}
preveMd5 = currentMd5
console.log(`${filePath}文件发生更新`)
})
Сначала сохраните значение md5 текущего файла, и каждый раз, когда файл изменяется (то есть после ответа на операцию сохранения), каждый раз получайте md5 файла и сравнивайте его, чтобы увидеть, есть ли какие-либо изменения.
Однако видно, что когда он будет сохранен в первый раз, он будет выполнен один раз, потому что исходное значение равно нулю. Таким образом, можно добавить совместимость, которая оценивается в зависимости от того, сохраняется ли она в первый раз.
оптимизация
Для разных операционных систем при сохранении может срабатывать более одного обратного вызова (макинтош не появляется). Чтобы избежать частых срабатываний, соответствующих этому отклику в реальном времени, для обеспечения производительности можно ввести функцию устранения дребезга.
const fs = require('fs'),
md5 = require('md5');
let preveMd5 = null,
fsWait = false
const filePath = './'
console.log(`正在监听 ${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
console.log(`${filePath}文件发生更新`)
}
})
заключительные замечания
На этом реализация файла мониторинга узла завершена. Сделайте учебную заметку, чтобы сделать справочную запись. Это не сложно реализовать, но есть много аспектов, которые необходимо учитывать для практического применения. По-прежнему рекомендуется использовать фреймворки с открытым исходным кодом, такие как node-watch, chokidar и т. д., которые относительно полны во всех аспектах.Для получения дополнительной информации перейдите в мой блог
Справочная статья
документация узла
How to Watch for Files Changes in Node.js
Nodejs Monitor File Changes