nodejs后台babel在线热编译jsx

浏览器加载react/vue组件时,遇到es6转es5,jsx转js...时,一种方法是用webpack离线编译,一种方法是在后台用babel在线热编译(为了效率部署前可以预热)。

我比较喜欢在线热编译,好处是发布时快,不经过build直接源码发布,并可以避免忘记编译步骤导致bug。

为了提供效率,把热编译结果保存为文件缓存起来。先检查是否有编译后缓存文件且没有过期,有就直接读取,否者编译后再读取。

node.js代码。

let fs=require('fs');
let babel = require("@babel/core");
let babel_preset_env=require('@babel/preset-env');
let babel_preset_react=require("@babel/preset-react");function transform(f,cb){let fc=f+'.js';function _trans(){fs.readFile(f,'utf8',function(err,code){if (err){cb(err)}else{let r=babel.transformSync(code,{presets:[babel_preset_env,babel_preset_react]});code=r.code;cb(null,code);fs.writeFile(fc,code,function(err){});}});}fs.lstat(fc,function(err,fcStat){if (err){_trans();}else{fs.lstat(f,function(err,fStat){if (err) cb(err);else{if (fcStat.birthtimeMs<fStat.mtimeMs){_trans();}else{fs.readFile(f,'utf8',function(err,code){cb(err,code);});}}});}});
}
transform('s.jsx');

但在多并发时,问题来了:多个并发任务可能会同时都检查到缓存不存在,然后开始编译.......很浪费,其实只需要一个任务来编译,其它任务等待编译结束后再读取缓存。

其实有点复杂,涉及到文件锁机制,阿里“通义千问”建议用proper-lockfile,我没用。模拟一下:

/*** 测试多进程下,判断一个文件是否存在,不存在才生成内容创建文件* 难点:* (1)避免多个进程在生成文件内容。* (2)一个进程如何等待正在生成文件的进程生成完成再读取。* (3)等待的效率,降低cpu占用*/
let path=require('path');
let fs=require('fs');
let fn=path.join(__dirname,'a.txt');function rw5(task){let fnlock=fn+'.lock';//递归获取锁function lock(cb){fs.open(fnlock,'wx',function(err,fhandle){if (err){console.log(task,' locked,try again...');setTimeout(function(){lock(cb);},1);}else{fs.close(fhandle,function(err){if (err) console.log(err);console.log(task,' got lock');cb();});}});}function unlock(){fs.unlink(fnlock,function(err){if (err) console.log(err)});}function read(cb){fs.readFile(fn,'utf8',function(err,data){//读不到正在写入的内容if (err) console.log(err);else console.log(task,' readed:',data);if (cb) cb();});}function write(cb){let content='hello';//用setTimeout模拟一个长时间的content计算过程,比如babel转码setTimeout(function(){fs.writeFile(fn,content,function(err,data){console.log(task,' writed:',content);if (cb) cb();});}, 1000);}fs.access(fn,function(err,data){if (err){console.log(task,' not exists');lock(function(){fs.access(fn,function(err,data){if (err){console.log(task,' not exists');write(function(){unlock();});}else{read(function(){unlock();});}});});}else{read();}});
}
rw5(1);
rw5(2);

看到的运行记录,可能如下:

D:\work\Source\yujiang.Foil.Node\test\filerw>node multirw.js
1  not exists
2  not exists
1  got lock
2  locked,try again...
1  not exists
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
2  locked,try again...
1  writed: hello
2  locked,try again...
2  got lock
2  readed: hello

封装一下:

yjFile.js

let fs=require('fs');
let path=require('path');
let debug=[console.log,function(){}][0];
/*** 热转换文件,有缓存文件且没有过期时,直接读取,否则转换后保存读取。* 考虑了异步并发的状况,转化动作只会有一个任务执行,其它等待。* @param {*} ops * @param {string} ops.fSource 源文件* @param {string} ops.fTarget 转码后的文件* @param {int} ops.tryLockInterval 尝试锁定文件的时间间隔,单位:毫秒,预设值:1。数字越大,cpu占用越少,但任务时间拖得越长。* @param {any} ops.taskID debug时日志显示的函数调用任务ID*/
function hotTransform(ops){if (!ops) ops={};if (ops.tryLockInterval==undefined) ops.tryLockInterval=1;let fLock=ops.fSource+'.lock';//递归获取锁function lock(cb){debug(ops.taskID,'try lock...');fs.open(fLock,'wx',function(err,fHandle){if (err){setTimeout(function(){lock(cb);},ops.tryLockInterval);}else{fs.close(fHandle,function(err){if (err) debug(ops.taskID,err);debug(ops.taskID,'......got lock');cb();});}});}function unlock(){fs.unlink(fLock,function(err){if (err) debug(ops.taskID,err)});debug(ops.taskID,'unlock');}function read(cb){fs.readFile(ops.fTarget,'utf8',function(err,data){if (err){debug(ops.taskID,err);}else{debug(ops.taskID,'readed:',data);}if (cb) cb();ops.cb(err,data);});}function write(data,cb){fs.writeFile(ops.fTarget,data,function(err,data2){if (err){if (err.code=='ENOENT'){let dir=path.dirname(ops.fTarget);fs.mkdir(dir,function(err){if (err){if (cb) cb(err);}else{write(data,cb);}});}else{if (cb) cb();debug(ops.taskID,err);}}else{if (cb) cb();debug(ops.taskID,'========= writed:',data);}});}function trans(){function handleError(e){unlock();debug(ops.taskID,e);ops.cb(e);}function _t(){ops.transform(function(err,data){if (err){handleError(err);}else{try{write(data,function(err){unlock();//注意:ops.cb要放在这里,如果放在write外面,可能ops.cb通知任务结束,子进程马上被杀掉,unlock不会被执行到。ops.cb(err,data);});}catch(e){handleError(e);}}});}lock(function(){//要加锁后,才能读写ops.fTarget文件。要保证能解锁。try{fs.lstat(ops.fTarget,function(err,targetStat){try{if (err){debug(ops.taskID,'locked,not exists');_t();}else{fs.lstat(ops.fSource,function(err,sourceStat){if (err) handleError(err);else{if (targetStat.birthtimeMs<sourceStat.mtimeMs){debug(ops.taskID,'locked,expired');_t();}else read(function(){unlock();});}});}}catch(e){handleError(e);}});}catch(e){handleError(e);}});}//为了效率:先判断缓存文件是否可用,可用直接用,否则要进入trans转码(转码锁文件效率很低)fs.lstat(ops.fTarget,function(err,targetStat){if (err){debug(ops.taskID,'not exists');trans();}else{fs.lstat(ops.fSource,function(err,sourceStat){//并发时,这时可能ops.fTarget已经更新了,无所谓,只是进入trans再加锁读取。if (err){ops.cb(err);}else{if (targetStat.birthtimeMs<sourceStat.mtimeMs){trans();}else read();}});}});
}
module.exports.hotTransform=hotTransform;

测试一下:

testCase_hotTransform.js

let path=require('path');
let fs=require('fs');
let yjFile=require('../../src/yjFile.js');const CNST_taskCount=5;
let endTaskCount=0;
let fSource=path.join(__dirname,'s.txt');
let ops={fSource,fTarget:path.join(__dirname,'dist/t.txt'),transform(cb){fs.readFile(fSource,'utf8',function(err,data){data=data+',tranformed.';cb(err,data);});},cb(err,data){let t2=new Date().getTime();console.log('-------',this.taskID,t2-this.startTime+'ms',err,data);endTaskCount++;if (endTaskCount==CNST_taskCount){if (process.send){process.send({cmd:'end'});}}}
}function start(taskID,waitTime){//增加延迟,让子进程的任务和主进程的任务尽量能同时并发执行,增加并发碰撞机会。//至少主进程内的2个任务是并发的,子进程内的2个任务是并发的。setTimeout(function(){for(let i=0;i<CNST_taskCount;i++){let ops1=Object.assign({taskID:taskID+i},ops);ops1.startTime=new Date().getTime();//console.log(ops1);yjFile.hotTransform(ops1);}},waitTime);
}process.on("message",function({cmd,data}){switch (cmd){case 'start':start(data.taskID,0);break;}
});module.exports.start=start;
module.exports.taskCount=CNST_taskCount;

run.js

let path=require('path');
let {fork} = require('child_process');
let testProcess = fork(path.join(__dirname,'testCase_hotTransform.js'));
testProcess.send({cmd:'start',data:{taskID:1}},function(err,data){let test=require('./testCase_hotTransform.js');//增加延迟,让子进程的任务和主进程的任务大概能“同时”进行,才能真正模拟并发。//否则,总是主进程发起的任务先执行完。test.start(test.taskCount+1,100);
});
testProcess.on("message",function({cmd,data}){switch (cmd){case 'end':testProcess.kill();break;}
});

主进程开启5个并发,并fork一个子进程,子进程里面也开启5个并发。

先随便建立一个s.txt文件,node run.js执行,可能看到的结果:

D:\work\Source\yujiang.Foil.Node\test\filerw>node run.js
6 not exists
6 try lock...
7 not exists
7 try lock...
8 not exists
8 try lock...
9 not exists
9 try lock...
10 not exists
10 try lock...
6 ......got lock
7 try lock...
8 try lock...
9 try lock...
10 try lock...
6 locked,not exists
1 not exists
7 try lock...
8 try lock...
9 try lock...
1 try lock...
10 try lock...
2 not exists
2 try lock...
7 try lock...
8 try lock...
9 try lock...
3 not exists
3 try lock...
4 not exists
10 try lock...
4 try lock...
7 try lock...
5 not exists
8 try lock...
5 try lock...
9 try lock...
1 try lock...
2 try lock...
10 try lock...
7 try lock...
3 try lock...
8 try lock...
4 try lock...
9 try lock...
6 unlock
5 try lock...
------- 6 56ms undefined source,tranformed.
6 ========= writed: source,tranformed.
1 try lock...
10 try lock...
7 try lock...
2 try lock...
3 try lock...
4 try lock...
5 ......got lock
8 try lock...
1 try lock...
9 try lock...
2 try lock...
10 try lock...
3 try lock...
7 try lock...
4 try lock...
1 try lock...
2 try lock...
3 try lock...
4 try lock...
5 readed: source,tranformed.
5 unlock
------- 5 52ms null source,tranformed.
1 try lock...
8 try lock...
2 try lock...
3 try lock...
9 try lock...
4 try lock...
10 try lock...
2 try lock...
7 try lock...
1 ......got lock
3 try lock...
4 try lock...
1 readed: source,tranformed.
1 unlock
------- 1 72ms null source,tranformed.
2 try lock...
3 try lock...
4 try lock...
8 try lock...
9 try lock...
10 try lock...
7 try lock...
3 try lock...
2 ......got lock
8 try lock...
9 try lock...
4 try lock...
10 try lock...
3 try lock...
7 try lock...
4 try lock...
8 try lock...
3 try lock...
9 try lock...
10 try lock...
2 readed: source,tranformed.
7 try lock...
2 unlock
------- 2 83ms null source,tranformed.
4 try lock...
3 try lock...
4 ......got lock
8 try lock...
9 try lock...
10 try lock...
3 try lock...
7 try lock...
8 try lock...
4 readed: source,tranformed.
4 unlock
------- 4 93ms null source,tranformed.
3 try lock...
3 ......got lock
3 readed: source,tranformed.
3 unlock
------- 3 98ms null source,tranformed.
9 try lock...
10 try lock...
7 try lock...
8 try lock...
9 ......got lock
10 try lock...
7 try lock...
8 try lock...
10 try lock...
7 try lock...
8 try lock...
9 readed: source,tranformed.
9 unlock
------- 9 131ms null source,tranformed.
10 try lock...
7 try lock...
8 try lock...
10 ......got lock
7 try lock...
8 try lock...
7 try lock...
10 readed: source,tranformed.
10 unlock
------- 10 142ms null source,tranformed.
8 try lock...
7 try lock...
8 ......got lock
7 try lock...
8 readed: source,tranformed.
8 unlock
------- 8 148ms null source,tranformed.
7 try lock...
7 ......got lock
7 readed: source,tranformed.
7 unlock
------- 7 157ms null source,tranformed.

从结果看,10个并发任务,各自消耗的时间为:

------- 6 56ms
------- 5 52ms
------- 1 72ms
------- 2 83ms
------- 4 93ms
------- 3 98ms
------- 9 131ms
------- 10 142ms
------- 8 148ms
------- 7 157ms

第一个完成的任务是6号,会面等待的任务,本应该马上获得数据结束,但是花了太多的时间在try lock上。如何再提高效率?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/9715.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++动态内存管理:与C语言动态内存管理的差异之争

当你改错一行代码的时候&#xff1a; 当你想要重构别人的代码时&#xff1a; 目录 前言 一、C/C的内存分布 二、C/C语言中的动态内存管理 三、new与delete的实现原理 总结&#xff1a; 前言 在C中&#xff0c;内存管理是一个至关重要的主题。正确地管理内存可以避免内存泄…

TriCore: Architecture

说明 本文是 英飞凌 架构文档 TriCore TC162P core archiecture Volume 1 of 2 (infineon.com) 的笔记&#xff0c;稍作整理方便查阅&#xff0c;错误之处&#xff0c;还请指正&#xff0c;谢谢 :) 1. Architecture 2. General Purpose & System Register 名词列表&#…

博客搭建666

title: 博客搭建 date: 2021-01-31 22:51:49 tags: hexo categories: 生活 toc_number: true篇幅有限 完整内容及源码关注公众号:ReverseCode,发送 冲 Hexo https://nodejs.org/download/release/v10.15.3/ 安装node npm install -g cnpm --registry=https://registry.npm…

佛山市举办2024年护士节庆祝活动

“作为一名在护理岗位上工作了39年的护士,能够在退休前参加这样温情的护士节活动,获得一个纪念胸章和一份荣誉证书,让我很感动!”第七届“南粤好护士”、佛山市第一人民医院急诊科护士长罗银秋说道。5月10日下午,由佛山市卫生健康局主办、佛山市护理学会协办、佛山市第一人民医…

KIE关键信息抽取——SDMG-R

https://arxiv.org/pdf/2103.14470https://arxiv.org/pdf/2103.14470 1.概述 背景:传统的关键信息提取方法依赖于模板匹配,这使它们难以泛化到未见过的模板,且对文本识别错误不够鲁棒。SDMG-R方法:提出一种端到端的双模态图推理方法,通过构建双模态图(视觉和文本特征),…

Python远程连接Linux执行操作

一、任务要求 要使用Python编写代码来远程给Linux主机上传一个文件&#xff0c;可以使用paramiko库&#xff0c;这是一个实现了SSHv2协议的Python库&#xff0c;它支持SSH连接&#xff08;包括客户端和服务端&#xff09;&#xff0c;并且提供SFTP&#xff08;SSH File Transf…

Vision Mamba:高效视觉表示学习双向状态空间模型,超越Vision Transformer!

DeepVisionary 每日深度学习前沿科技推送&顶会论文分享&#xff0c;与你一起了解前沿深度学习信息&#xff01; Vision Mamba: Efficient Visual Representation Learning with Bidirectional State Space Model 引言&#xff1a;探索视觉领域的新方向 在计算机视觉领域&…

地球行星UE5和UE4

地球行星&#xff0c;包含多种地球风格&#xff0c;可蓝图控制自转和停止&#xff0c;可材质自转. 支持版本4.21-5.4版本 下载位置&#xff1a;https://mbd.pub/o/bread/ZpWZm5lv b站工坊&#xff1a;https://gf.bilibili.com/item/detail/1105582041 _______________________…

luceda ipkiss教程 68:通过代码模板提高线路设计效率

在用ipkiss设计器件或者线路时&#xff0c;经常需要输入: from ipkiss3 import all as i3那么有什么办法可以快速输入这段代码呢&#xff1f;这里就可以利用Pycharm的 live template功能&#xff0c;只需要将文件&#xff1a;ipkiss.xml &#xff08;luceda ipkiss教程 68&…

浏览器a标签下载txt、json文件自动打开预览的问题

背景 由于浏览器的特性.txt .pdf .json 等等文件放在a标签的href属性中会被浏览器直接打开&#xff0c;这时可以给a添加download属性强制下载&#xff0c;但是当执行 跨域下载 文件时download属性就会失效。 解决办法 跨域会导致download属性失效&#xff0c;使用xhr下载方式…

Vue3:项目创建

Vue 3 相对于 Vue 2 带来了许多改进和优点&#xff0c;这些改进主要是为了提高性能、开发体验和可维护性。但是对于创建项目&#xff0c;Vue3也可以采用跟Vue2相同的方式。 使用CLI创建 1. 安装Vue CLI 首先&#xff0c;确保你已经安装了Node.js&#xff08;建议使用LTS版本…

金蝶向左,用友向右

【科技明说 &#xff5c; 科技热点关注】 科技明说分析指出&#xff0c;金蝶和用友作为国内数一数二的财务软件巨头&#xff0c;两者不仅是竞争对手&#xff0c;也是很好的发展队友&#xff0c;在云计算时代、AI时代都相继进行了不同程度的产品与服务创新。与时俱进的好处&…

如何将图片表格转成excel?分享3种好用的软件!

在信息爆炸的时代&#xff0c;我们每天都会接触到大量的图片表格。这些表格中可能包含着我们需要的各种数据和信息&#xff0c;但是如何将它们快速、准确地转化为Excel格式&#xff0c;以便我们进行编辑、分析呢&#xff1f;今天&#xff0c;就让我们一起来探讨一下如何将图片表…

图形网络的自适应扩散 笔记

1 Title Adaptive Diffusion in Graph Neural Networks&#xff08;Jialin Zhao、Yuxiao Dong、Ming Ding、Evgeny Kharlamov、Jie Tang&#xff09;【NIPS 2021】 2 Conclusion The neighborhood size in GDC is manually tuned for each graph by conductin…

AXI4写时序在AXI Block RAM (BRAM) IP核中的应用

在本文中将展示描述了AXI从设备&#xff08;slave&#xff09;AXI BRAM Controller IP核与Xilinx AXI Interconnect之间的写时序关系。 1 Single Write 图1是一个关于32位宽度的BRAM&#xff08;Block RAM&#xff09;的单次写入操作的例子。这个例子展示了如何向地址0x1000h…

MySQL——变量的浮点数问题处理

新建链接&#xff0c;自带world数据库&#xff0c;里面自带city表格。 DQL #MySQL变量的浮点数问题处理 set dx3.14,dy3.25; select dxdy;#计算显示异常&#xff0c;会有很多00000的提示set resultdxdy; select result; 查询结果

Jetson AGX Orin平台搭建whisper语音转写实时录音

1&#xff1a;下载whisper C版本 whisper.cpp 编译WHISPER_CUDA1 make -j 错误 A: 平台不支持&#xff0c;修改Makefile&#xff0c;查看支持的计算ARCH_FLAG nvcc fatal : Value all is not defined for option gpu-architecture make: *** [Makefile:290: ggml-cuda.o…

C++青少年简明教程:C++中的常量、变量、表达式和语句

C青少年简明教程&#xff1a;C中的常量、变量、表达式和语句 在C编程中&#xff0c;常量、变量、表达式和语句是基本的编程概念。 常量&#xff08;Constants&#xff09;&#xff1a;在程序中具有固定值的数据称为常量。常量可以是字面值&#xff0c;如整数、浮点数、字符或…

Linux 第二十六章

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C&#xff0c;linux &#x1f525;座右铭&#xff1a;“不要等到什么都没有了…

【挑战30天首通《谷粒商城》】-【第一天】【10 番外篇】 解决docker 仓库无法访问 + MobaXterm连接VirtualBox虚拟机

文章目录 课程介绍 1、解决docker 仓库无法访问 2、 MobaXterm连接VirtualBox虚拟机 Stage 1&#xff1a;下载MobaXterm选择适合你的版本 Stage 2&#xff1a;vagrant ssh 连接&#xff0c;开启ssh访问 Stage 2-1&#xff1a;su获取root账号权限,输入密码&#xff08;默认vagra…