需求
- 每次打开Vscode编辑器执行任务。
- 只有打开指定的文件夹后脚本的实际内容才会被真正执行。
- 在指定的文件夹下创建JavaScript文件后,会在文件开头生成更新此文件的时间,精确到秒。
- 每次保存后:
- 如果当前时间距离上一次更新时间 > 24小时,则另起一行生成新的时间注释。
- 如果当前时间距离上一次更新时间 < 24小时,则覆盖之前的时间注释。
成果展示:
设置任务
- 在 VS Code 中,打开命令面板(
Ctrl+Shift+P
),然后输入 “Tasks: Configure Task” 并选择它。 - 在弹出的菜单中,选择 “Create tasks.json file from template”,然后选择 “Others”。
- 这将会在你的工作区的
.vscode
文件夹中创建一个tasks.json
文件。在这个文件中,你可以定义你的任务。 - 在
tasks.json
文件中,你可以设置你的任务的label
(标签),type
(类型),command
(命令)和args
(参数)。command
应该是你的脚本的路径,args
应该是你想要处理的文件夹的路径。 - 你还可以设置
presentation
属性来控制任务的输出和运行方式。例如,你可以设置reveal
为always
来总是在输出面板中显示任务的输出。
task.json
文件
{
"version": "2.0.0",
"tasks": [
{
"label": "Update Date Comment",
"type": "shell",
"command": "node",
"args": ["./self_practice/updateDateComment.js", "./self_practice/每日练习"],
"presentation": {
"reveal": "always"
},
"problemMatcher": [],
"runOptions": {
"runOn": "folderOpen"
}
}
]
}
代码展示
const fs = require('fs');
const path = require('path');
const folderPath = './self_practice/每日练习'; // 你的文件夹路径
let watcher;
// 防抖函数
function debounce(func, wait) {
let timeout = null;
return function () {
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(() => {
func.apply(this, arguments);
timeout = null;
}, wait);
};
}
// 替换注释等操作
function changeComments(filePath) {
// 只处理.js文件
if (path.extname(filePath) === '.js') {
try {
let content = fs.readFileSync(filePath, 'utf8');
let lines = content.split('\n');
let now = new Date();
let dateComment = `// Last updated: ${now.toLocaleString()}`;
if (lines[0].startsWith('// Last updated:')) {
let oldDateStr = lines[0].replace('// Last updated: ', '');
// 由于toLocaleString()的结果可能因浏览器和地区设置的不同而不同,我们需要将其转换回时间戳进行比较
if (now.getTime() - Date.parse(oldDateStr) >= 24 * 60 * 60 * 1000) {
// 如果距离上次更新超过24小时,添加新的注释
lines.unshift(dateComment);
} else {
// 否则,覆盖旧的注释
lines[0] = dateComment;
}
} else {
lines.unshift(dateComment);
}
let newContent = lines.join('\n');
fs.writeFileSync(filePath, newContent, 'utf8');
} catch (error) {
if (error.code !== 'EBUSY') {
throw error;
}
// 如果文件正在被使用,忽略错误
}
}
}
// 更新文件的日期注释
function updateDateComment(filePath) {
// 检查self_practice文件夹是否存在
if (!fs.existsSync(filePath)) {
console.log('self_practice folder does not exist. Exiting...');
return;
}
// 停止监视文件
watcher.close();
changeComments(filePath)
// 重新开始监视文件
startWatching();
}
function startWatching() {
watcher = fs.watch(folderPath, (eventType, filename) => {
if (filename && (eventType === 'change' || eventType === 'rename')) {
const filePath = path.join(folderPath, filename);
console.log('watching folder')
debouncedUpdateDateComment(filePath);
}
});
}
// 使用防抖函数,延迟1秒执行
const debouncedUpdateDateComment = debounce(updateDateComment, 1000);
// 开始监视文件
startWatching();
BUG解决方案
-
保存操作频率过快导致文件写入操作产生"竞态条件"(Race Condition)的问题,即如果你的代码正在尝试读取或者写入文件,而你又在同一时间保存文件,那么你的代码可能会读取到一个旧的文件版本,或者你的保存操作可能会覆盖你的代码的修改。
-
保存一次,监视文件修改的函数会被执行几百次,性能非常差。
引入防抖函数!限制操作的频率,同时将多次操作保存为一次!
-
引入防抖函数导致的循环:当脚本修改文件时(覆盖注释)——
fs.watch
触发change事件——脚本再次修改文件(覆盖注释)——…- 在修改文件之前,先停止监视文件。
- 文件修改完成后再开始监视。