Node.js是一个基于ChromeV8引擎的JavaScript运行时。2020年10月27日,Node.jsv14.15.0LTS版本发布,这是长期支持版本,包含许多很棒的新特性。以下内容也是基于笔者日常的Node.js工作和学习。总结,可能不完整,也欢迎补充,之前已经单独写了一些功能来介绍,我们来看看有哪些新的变化?可选链(OptionalChaining)如果我们使用JavaScript,不管是用在前端还是Node。这样判断,你可能会得到类似Cannotreadproperty'xxx'ofundefined的错误。constuser={name:'Tom',address:{city:'ZhengZhou'}}if(user&&user.address){console.log(user.address.city)}现在我们有了一种优雅的写法“可选链运算符”,不需要显式验证链中的每个引用是否有效,用符号“?.”表示,当引用为null或undefined时不会报错,短路会返回undefined发生。user.address?.cityuser.address?.city?.length//与?.[]结合访问相当于user.address['city']user.address?.['city']//结合使用用delete语句,只有当user.address.city存在时才删除user.address?.city,返回false值时,返回右边的运算符。例如,如果我们传入一个属性为enabled:0并且我们期望输出左边的值,它就不起作用。functionComponent(props){constenable=props.enabled||true;//true}Component({enabled:0})现在我们可以使用**空值合并运算符(??)**来实现,只要左边右侧的值仅在未定义或null时返回。functionComponent(props){constenable=props.enabled??true;//0}Component({enabled:0})参考:https://v8.dev/features/nullish-coalescingIntl.DisplayNames(国际化显示名称)为国际化应用程序需要使用的语言、地区、货币和文字的名称。现在JavaScript开发人员可以使用Intl.DisplayNamesAPI直接访问这些翻译,使应用程序更容易显示本地化名称。Language(语言)letlongLanguageNames=newIntl.DisplayNames(['zh-CN'],{type:'language'});longLanguageNames.of('en-US');//美式英语longLanguageNames.of('zh-CN');//中文(中国)longLanguageNames=newIntl.DisplayNames(['en'],{type:'language'});longLanguageNames.of('en-US');//AmericanEnglishlongLanguageNames.of('zh-CN');//Chinese(China)Region(地区)letregionNames=newIntl.DisplayNames(['zh-CN'],{type:'region'});regionNames.of('US');//美国regionNames.of('419');//拉丁美洲regionNames=newIntl.DisplayNames(['en'],{type:'region'});regionNames.of('US');//UnitedStatesregionNames.of('419');//LatinAmericaCurrency(currency)letcurrencyNames=newIntl.DisplayNames(['zh-CN'],{type:'currency'});currencyNames.of('CNY');??//人民币currencyNames.of('USD');//美元currencyNames=newIntl.DisplayNames(['en'],{type:'currency'});currencyNames.of('CNY');??//人民币currencyNames.of('USD');//USDollarScript(Script)letscriptNames=newIntl.DisplayNames(['zh-CN'],{type:'script'});scriptNames.of('Hans');//简化的scriptNames.of('Latn');//LatinscriptNames=newIntl.DisplayNames(['en'],{type:'script'});scriptNames.of('Hans');//SimplifiedscriptNames.of('Latn');//拉丁文参考:https://v8.dev/features/intl-displaynames上面例子中使用的国家代码和代码可以从参考地址中获取。Intl.DateTimeFormat(国际化日期和时间格式)Intl.DateTimeFormatAPI用于处理特定区域设置的日期格式。constdate=newDate();//Sunday,January10,2021at9:02:29PMGMT+8newIntl.DateTimeFormat('en-US',{dateStyle:'full',timeStyle:'long'}).format(date)//21/1/10中国标准时间9:02:29.315pmnewIntl.DateTimeFormat('zh-CN',{year:'2-digit',month:'numeric',day:'numeric',hour:'numeric',minute:'numeric',second:'numeric',fractionalSecondDigits:3,timeZoneName:'long'}).format(date)参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormatString.prototype.matchAll(throwsonnon-globalregex)matchAll()返回一个包含所有匹配正则表达式的结果,返回值是一个不可重用的(不可重用的意思是读后需要重新获得它)。Node.jsv12.4.0及以上版本已经支持matchAll()方法。这种方法有一个局限性。如果设置的正则表达式不包含全局模式g,如果Node.jsv14.5.0及以后版本没有提供,则会抛出TypeError异常。//constregexp=RegExp('foo[a-z]*','g');//更正constregexp=RegExp('foo[a-z]*');//错误,没有全局模式conststr='tablefootball,foosball,fo';constmatches=str.matchAll(regexp);//TypeError:String.prototype.matchAllcalledwithanon-globalRegExpargumentfor(constitemofmatches){console.log(item);}参考:https://node.green/#ES2020-features-String-prototype-matchAll-throws-on-non-global-regexAsyncLocalStorage(异步本地存储)Node.jsAsyncHooks模块提供了一个API来跟踪Node.js程序中异步资源的语句周期,在最新的v14中。x在LTS版本中,新增了一个AsyncLocalStorage类,方便实现context本地存储,异步调用之间共享数据,对于实现日志链接跟踪场景很有用。下面是一个HTTP请求的简单示例,模拟异步处理,并在日志输出中跟踪存储的id。consthttp=require('http');const{AsyncLocalStorage}=require('async_hooks');constasyncLocalStorage=newAsyncLocalStorage();functionlogWithId(msg){constid=asyncLocalStorage.getStore();console.log(`${id!==undefined?id:'-'}:`,msg);}letidSeq=0;http.createServer((req,res)=>{asyncLocalStorage.run(idSeq++,()=>{logWithId('start');setImmediate(()=>{logWithId('processing...');setTimeout(()=>{logWithId('finish');res.end();},2000)});});})。听(8080);下面是运行结果。我是在第一次打完后直接打了第二次。可以看到我们保存的id信息连同我们的log一起成功打印出来了。image.png的便利性也牺牲了一些性能。ES模块支持ES模块支持通常是一件好事。进一步规范了Node.js和浏览器的模块生态,使它们进一步收敛,避免进一步分裂。在当前的Node.jsv14.xLTS版本中已经移除了实验性支持,现在使用了no-use标志。它使用import和export关键字,有两种使用方式:使用.mjs扩展//caculator.mjsexportfunctionadd(a,b){returna+b;};//index.mjsimport{add}from'。/caculator.js';console.log(add(4,2));//6告诉Node.js将JavaScript代码视为Node.js默认将JavaScript代码视为ESModules的CommonJS规范,因此我们需要使用上面的扩展名.mjs声明它。此外,我们还可以在package.json文件中设置type字段为module或运行node时的标志--input-type=module告诉Node.js将JavaScript代码视为ES模块。//package.json{"name":"esm-project","type":"module",...}前端同学可能对以上ESModules的使用方法不陌生。Top-LevelAwait(顶级等待支持)顶级等待支持在异步函数之外使用await关键字。在Node.jsv14.xLTS版本中移除了实验性支持,现在不再需要使用flag。importfetchfrom'node-fetch';constres=awaitfetch(url)也可以像调用函数一样动态引入模块。constmyModule=awaitimport('./my-module.js');对于异步资源,我们之前不得不在async函数中使用await,这对于一些需要在文件顶部实例化的资源可能效果不佳。现在有了顶层的await,我们可以很方便的在文件的最前面对这些异步资源做一些初始化操作。诊断报告(diagnosticreport)诊断报告是Node.jsv14.xLTS提供的稳定功能,在某些情况下,它会生成JSON格式的诊断报告,可用于开发、测试和生产环境。报告提供有价值的信息,包括:JavaScript和本机堆栈信息、堆统计信息、平台信息、资源使用情况等,以帮助用户快速跟踪问题。https://github.com/IBM/report-toolkit是IBM开发的用于简化报告工具使用的工具。下面是一个会导致服务内存泄漏的简单demo。consttotal=[];setInterval(function(){total.push(newArray(20*1024*1024));//内存占用大,不会释放},1000)最终生成的json报告诊断报告-toolkit工具结果可能如下。新版本的Stream包含了对Stream的一些改动,旨在提高StreamAPI的一致性,消除歧义并简化Node.js核心各部分的行为,例如:http.OutgoingMessage和stream.Writable类似于net.套接字行为与stream.Duplex完全相同一个显着变化autoDestroy的默认值为true,使得流在结束后始终调用_destroy参考:https://nodejs.medium.com/node-js-version-14-available-now-8170d384567e使用异步迭代器使用异步迭代器,我们可以在Node.js中遍历事件、流或MongoDB返回值。这是一件非常有趣的事情,虽然它不是Node.jsv14.x中提出的新特性,例如event.on仅在Node.jsv12.16.0中被支持。这些目前介绍的不多,这里简单介绍一下。在Events中使用Node.js在v12.16.0中添加了events.on(emitter,eventName)方法,该方法返回一个异步迭代器,用于迭代eventName事件。比如启动一个Node.js服务可以这样写。想知道它的原理可以看笔者下面提到的相关文章。import{createServerasserver}from'http';import{on}from'events';constee=on(server().listen(3000),'request');forawait(const[{url},res]ofee)if(url==='/hello')res.end('HelloNode.js!');elseres.end('OK!');在Stream中使用,以往我们可以通过on('data')监听事件,通过异步迭代器可以更简单的方式实现读取数据。asyncfunctionreadText(readable){letdata='';forawait(constchunkofreadable){data+=chunk;}returndata;}当前没有在JavaScript中默认设置[Symbol.asyncIterator]属性的内置对象。一些Node.js在Events和Stream模块中是可用的,你也可以用它来遍历MongoDB返回的结果。
