当前位置: 首页 > 后端技术 > Node.js

NodeJS文档中读到的19个例程

时间:2023-04-03 18:09:44 Node.js

...本文属于作者Web开发入门与最佳实践中NodeJS入门与最佳实践系列文章。虽然我已经用了三年多的NodeJS,但我曾经以为我对它无所不知。但我似乎已经吸取了教训,还没有静静地坐下来仔细阅读NodeJS的完整文档。如果熟悉我的人应该知道,我之前阅读过HTML、DOM、WebAPIs、CSS、SVG和ECMAScript的文档,NodeJS是我系列中最后一座要读的山。在阅读文档的过程中,我也发现了很多以前不知道的知识,觉得有必要分享给大家。不过文档比较直白,所以我也按照阅读顺序列出来。要点要明白。querystring:一个可以用作通用解析器的模块。很多时候我们会从数据库或其他地方得到这种奇怪格式的字符串:name:Sophie;shape:fox;condition:new。一般来说,我们会使用字符串切割将字符串分割成JavaScript对象。但是querystring也是一个很好的现成工具:constweirdString=`name:Sophie;shape:fox;condition:new`;constresult=querystring.parse(weirdString,`;`,`:`);//result://{//name:`Sophie`,//shape:`fox`,//condition:`new`,//};V8Inspector使用-使用-inspect参数运行您的Node应用程序,它会给您一个URL。将URL复制到Chrome中并打开它,您可以使用ChromeDevTools来调试您的Node应用程序。详细的实验可以参考这篇文章。但是请注意,此参数仍处于试验阶段。nextTick和setImmediate的区别这两个产品从名字上可能看不出区别,我觉得应该起个别名:process.nextTick()应该是process.sendThisToTheStartOfTheQueue()setImmediate应该是sendThisToTheEndOfTheQueue()说不相关,React中的Props应该是stuffThatShouldStayTheSameIfTheUserRefreshes,State应该是stuffThatShouldBeForgottenIfTheUserRefreshes。Server.listen可以使用Object作为参数。我更喜欢调用带命名参数的函数,这比只遵循顺序的无名参数方法更直观。不要忘记Server.listen也可以使用对象作为参数:require(`http`).createServer().listen({port:8080,host:`localhost`,}).on(`request`,(req,res)=>{res.end(`HelloWorld!`);});但是,这个特性并没有在http.ServerAPI中表达,而是在其父net.Server的文档中。相对地址你传给fs模块的距离可以是相对地址,也就是相对于process.cwd()。估计早就有人知道了,但一直以为只能用绝对地址:constfs=require(`fs`);constpath=require(`path`);//为什么我总是这样做...fs.readFile(path.join(__dirname,`myFile.txt`),(err,data)=>{//做点什么});//我什么时候可以这样做?fs.readFile(`./path/to/myFile.txt`,(err,data)=>{//dosomething});PathParsing:路径解析之前不知道的一个功能是解析路径来自文件名、文件名、文件扩展名等:myFilePath=`/someDir/someFile.json`;path.parse(myFilePath).base===`someFile.json`;//truepath.parse(myFilePath).name===`someFile`;//truepath.parse(myFilePath).ext===`.json`;//trueLoggingwithcolors别忘了console.dir(obj,{colors:true})可以用不同的颜色打印键和值,这会大大增加日志的可读性。使用setInterval执行定时任务我喜欢使用setInterval执行定时的数据库清理任务,但是默认情况下NodeJS不会在setInterval存在的情况下退出,可以使用下面的方法让Node休眠:constdailyCleanup=setInterval(()=>{cleanup();},1000*60*60*24);dailyCleanup.unref();使用信号常数`SIGTERM`);这很好,但是由于第二个参数可以使用字符串和整数变量,所以最好使用全局变量:process.kill(process.pid,os.constants.signals.SIGTERM);IPAddressValidationNodeJS有内置IP地址验证工具,使您无需编写额外的正则表达式:require(`net`).isIP(`10.0.0.1`)返回4require(`net`)。isIP(`cats`)返回0os.EOF。不知道你有没有手写行尾,看起来不太好看。NodeJS内置了os.EOF,在Windows下是rn,其他地方是n。使用os.EOL可以让你的代码在不同的操作系统上保持一致:constfs=require(`fs`);//badfs.readFile(`./myFile.txt`,`utf8`,(??err,data)=>{data.split(`\r\n`).forEach(line=>{//做某事});});//好的constos=require(`os`);fs.readFile(`./myFile.txt`,`utf8`,(??err,data)=>{data.split(os.EOL).forEach(line=>{//做点什么});});HTTP状态码NodeJS帮助我们构建HTTP状态码及其描述,即http.STATUS_CODES,key是状态值,value是描述:可以这样使用:someResponse.code===301;//truerequire(`http`).STATUS_CODES[someResponse.code]===`永久移动`;//true避免异常崩溃有时候会遇到以下情况导致服务器崩溃还是蛮无奈的:constjsonData=getDataFromSomeApi();//但是,哦不,坏数据!常量数据=JSON.parse(jsonData);//巨大的撞击声。为了避免这种情况,我加了一个global:process.on(`uncaughtException`,console.error);当然,这种方法绝不是最佳实践。如果是在大项目中,我还是会用pm2,然后把所有可能的crash代码都加到try...catch中。只是这个once()除了on方法,once方法也适用于所有EventEmitter,希望我不是最后一个知道这个的:server.once(`request`,(req,res)=>res.end(`不再来自我。`));自定义控制台您可以使用newconsole.Console(standardOut,errorOut),然后设置自定义输出流。您可以选择创建一个控制台来将数据输出到文件或Socket或第三方。DNS查找一个小哥跟我说,Node不会缓存DNS查找信息,所以你在使用URL之后要等几毫秒才能拿到数据。但实际上,你可以使用dns.lookup()来缓存数据:dns.lookup(`www.myApi.com`,4,(err,address)=>{cacheThisForLater(address);});fs在不同操作系统上可用某些差异fs.stats()返回的对象中的模式属性在Windows和其他操作系统之间有所不同。fs.lchmod()仅适用于macOS。仅Windows支持使用类型参数调用fs.symlink()。在macOS和Windows上调用fs.watch()时仅传递递归选项。在Linux和Windows中,fs.watch()的回调可以传入一个文件名。使用fs.open()和a+属性打开目录时,仅在FreeBSD和Windows上有效,但在macOS和Linux上存在问题。.在Linux下以追加模式打开文件时,传递给fs.write()的位置参数将被忽略。net模块的速度几乎是http的两倍。在文档中看到了一些关于两者性能的讨论,我也跑了两台服务器进行了真实的对比。因此,http.Server每秒可以接收大约3400个请求,而net.Server可以接收大约5500个请求。//这建立了两个连接,一个连接到tcp服务器,一个连接到http服务器(都在server.js中)//它触发一堆连接并计算响应时间//两者都发送strings.constnet=require(`net`);consthttp=require(`http`);functionparseIncomingMessage(res){returnnewPromise((resolve)=>{letdata=``;res.on(`data`,(chunk)=>{data+=chunk;});res.on(`end`,()=>resolve(data));});}consttestLimit=5000;/*-------------------*//*--NET客户端--*//*------------------*/functiontestNetClient(){constnetTest={startTime:process.hrtime(),responseCount:0,testCount:0,payloadData:{type:`millipede`,feet:100,test:0,},};函数handleSocketConnect(){netTest.payloadData.test++;netTest.payloadData.feet++;constpayload=JSON.stringify(netTest.payloadData);this.end(payload,`utf8`);}函数handleSocketData(){netTest.re响应计数++;如果(netTest.responseCount===testLimit){consthrDiff=process.hrtime(netTest.startTime);constelapsedTime=hrDiff[0]*1e3+hrDiff[1]/1e6;constrequestsPerSecond=(testLimit/(elapsedTime/1000)).toLocaleString();console.info(`net.Server平均每秒处理${requestsPerSecond}个请求。`);}}while(netTest.testCount{httpTest.responseCount++;if(httpTest.responseCount===testLimit){consthrDiff=process.hrtime(httpTest.startTime);constelapsedTime=hrDiff[0]*1e3+hrDiff[1]/1e6;constrequestsPerSecond=(testLimit/(elapsedTime/1000)).toLocaleString();console.info(`http.Server平均每秒处理${requestsPerSecond}个请求。`);}});}while(httpTest.testCount{console.info(`StartingtestNet客户()`);testNetClient();},50);setTimeout(()=>{console.info(`StartingtestHttpClient()`);testHttpClient();},2000);//这设置了两个服务器。一个TCP和一个HTTP。//对于每个响应,它将接收到的字符串解析为JSON,转换该对象并返回一个字符串constnet=require(`net`);consthttp=require(`http`);functionrenderAnimalString(jsonString){常量数据=JSON.parse(jsonString);return`${data.test}:你是${data.type}并且你有${data.feet}英尺。`;}/*----------------*//*--网络服务器--*//*------------------*/net.createServer((socket)=>{socket.on(`data`,(jsonString)=>{socket.end(renderAnimalString(jsonString));});}).listen(8888);/*--------------------*//*--HTTP服务器--*//*------------------*/functionparseIncomingMessage(res){returnnewPromise((resolve)=>{letdata=``;res.on(`data`,(chunk)=>{data+=chunk;});res.on(`end`,()=>resolve(data));});}http.createServer().listen(8080).on(`request`,(req,res)=>{parseIncomingMessage(req).then((jsonString)=>{res.end(renderAnimalString(jsonString));});});REPLtricks如果你是REPL模式,可以直接进入node,进入交互模式。你可以直接输入.loadsomeFile.js然后你可以加载一个包含自定义常量的文件。您可以通过设置NODE_REPL_HISTORY=""来避免将日志写入文件。_用于记录最后一次计算的值。REPL启动后,所有模块直接加载成功。可以与os.arch()一起使用,而不是require(os).arch()。