NodeJs-Single Executable Applications
小卒子

NodeJs-Single Executable Applications

单一可执行应用程序稳定性:1.1-活跃开发中该功能允许方便地将Node.js应用程序分发到没有安装Node.js的系统上。Node.js通过允许将由Node.js准备的blob注入到node二进制文件中,从而支持创建单一可执行应用程序https://github.com/nodejs/single-executablehttps://github.com/nodejs/single-executable。该blob可以包含一个打包好的脚本。在启动时,程序会检查是否有注入内容。如果找到blob,它会执行blob中的脚本。否则,Node.js将按正常方式运行。目前,单一可执行应用程序功能仅支持使用CommonJSmodules.md#modules-commonjs-modulesmodules.md#modules-commonjs-modules模块系统运行单个嵌入式脚本。用户可以使用node二进制文件及任何能够将资源注入二进制文件的工具来创建单一可执行应用程序。以下是使用其中一种工具postjecthttps://github.com/nodejs/postjecthttps://github.com/nodejs/postject创建单一可执行应用程序的步骤:创建一个JavaScript文件:echo'console.log(`Hello,${process.argv[2]}!`);'>hello.js创建一个配置文件来构建可以注入到单一可执行应用程序中的blob(详细信息见生成单一可执行准备blob#生成单一可执行准备-blob#生成单一可执行准备-blob):echo'{"main":"hello.js","output":"sea-prep.blob"}'>sea-config.json生成要注入的blob:node--experimental-sea-configsea-config.json创建node可执行文件的副本,并根据需要命名:在非Windows系统上:cp$(command-vnode)hello在Windows上:node-e"require('fs').copyFileSync(process.execPath,'hello.exe')".exe扩展名是必要的。删除二进制文件的签名(仅限macOS和Windows):在macOS上:codesign--remove-signaturehello在Windows上(可选):signtoolhttps://learn.microsoft.com/en-us/windows/win32/seccrypto/signtoolhttps://learn.microsoft.com/en-us/windows/win32/seccrypto/signtool可以从已安装的WindowsSDKhttps://developer.microsoft.com/en-us/windows/downloads/windows-sdk/https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/中使用。如果跳过此步骤,忽略postject的签名相关警告。signtoolremove/shello.exe通过运行postject注入blob到复制的二进制文件中,使用以下选项:hello/hello.exe-第4步中创建的node可执行文件副本的名称。NODE_SEA_BLOB-blob内容将存储在二进制文件中的资源/注释/部分的名称。sea-prep.blob-第1步中创建的blob的名称。--sentinel-fuseNODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2-Node.js项目用于检测是否注入了文件的fusehttps://www.electronjs.org/docs/latest/tutorial/fuseshttps://www.electronjs.org/docs/latest/tutorial/fuses。--macho-segment-nameNODE_SEA(仅macOS需要)-二进制文件中存储blob内容的段的名称。总结如下:在Linux上:npxpostjecthelloNODE_SEA_BLOBsea-prep.blob\--sentinel-fuseNODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2在Windows-PowerShell上:npxpostjecthello.exeNODE_SEA_BLOBsea-prep.blob`--sentinel-fuseNODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2在Windows-命令提示符下:npxpostjecthello.exeNODE_SEA_BLOBsea-prep.blob^--sentinel-fuseNODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2在macOS上:npxpostjecthelloNODE_SEA_BLOBsea-prep.blob\--sentinel-fuseNODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2\--macho-segment-nameNODE_SEA签名二进制文件(仅限macOS和Windows):在macOS上:codesign--sign-hello在Windows上(可选):需要一个证书才能成功签名。然而,未签名的二进制文件仍然可以运行。signtoolsign/fdSHA256hello.exe运行二进制文件:在非Windows系统上:$./helloworldHello,world!在Windows上:$.\hello.exeworldHello,world!生成单一可执行准备blob可以使用--experimental-sea-config标志和将用于构建单一可执行文件的Node.js二进制文件生成单一可执行准备blob。它接受一个JSON格式的配置文件路径。如果传递的路径不是绝对路径,Node.js将使用相对于当前工作目录的路径。配置文件目前读取以下顶级字段:{"main":"/path/to/bundled/script.js","output":"/path/to/write/the/generated/blob.blob","disableExperimentalSEAWarning":true,//默认:false"useSnapshot":false,//默认:false"useCodeCache":true,//默认:false"assets":{//可选"a.dat":"/path/to/a.dat","b.txt":"/path/to/b.txt"}}如果路径不是绝对路径,Node.js将使用相对于当前工作目录的路径。生成blob的Node.js二进制文件版本必须与将blob注入到的版本相同。注意:在生成跨平台SEA(例如,在darwin-arm64上生成linux-x64的SEA)时,必须将useCodeCache和useSnapshot设置为false,以避免生成不兼容的可执行文件。由于代码缓存和快照只能在编译它们的平台上加载,因此生成的可执行文件在尝试加载在不同平台上构建的代码缓存或快照时可能会崩溃。Assets用户可以通过在配置文件中添加一个key-path字典来包含资产,作为assets字段。在构建时,Node.js将从指定的路径读取资产并将其打包到准备blob中。在生成的可执行文件中,用户可以使用sea.getAsset()#seagetassetkey-encoding#seagetassetkey-encoding和sea.getAssetAsBlob()#seagetassetasblobkey-options#seagetassetasblobkey-optionsAPI检索这些资产。{"main":"/path/to/bundled/script.js","output":"/path/to/write/the/generated/blob.blob","assets":{"a.jpg":"/path/to/a.jpg","b.txt":"/path/to/b.txt"}}单一可执行应用程序可以按如下方式访问资产:const{getAsset,getAssetAsBlob,getRawAsset}=require('node:sea');//返回以ArrayBuffer形式的资产数据副本。constimage=getAsset('a.jpg');//返回解码为UTF8的资产字符串。consttext=getAsset('b.txt','utf8');//返回包含资产的Blob。constblob=getAssetAsBlob('a.jpg');//返回包含原始资产的ArrayBuffer。constraw=getRawAsset('a.jpg');有关sea.getAsset()#seagetassetkey-encoding#seagetassetkey-encoding,sea.getAssetAsBlob()#seagetassetasblobkey-options#seagetassetasblobkey-options和sea.getRawAsset()#seagetrawassetkey#seagetrawassetkeyAPI的更多信息,请参阅文档。启动快照支持可以使用useSnapshot字段来启用启动快照支持。在这种情况下,main脚本不会在最终可执行文件启动时运行。相反,它将在构建机器上运行时运行。生成的准备blob将包括捕获main脚本初始化的状态的快照。最终的可执行文件将会在运行时反序列化快照。当useSnapshot为true时,main脚本必须调用v8.startupSnapshot.setDeserializeMainFunction()v8.md#v8startupsnapshotsetdeserializemainfunctioncallback-datav8.md#v8startupsnapshotsetdeserializemainfunctioncallback-dataAPI来配置在用户机器上启动时需要运行的代码。使用快照的单一可执行应用程序的典型模式是:在构建时,在构建机器上运行main脚本,以将堆初始化到一个准备接受用户输入的状态。脚本还应使用v8.startupSnapshot.setDeserializeMainFunction()v8.md#v8startupsnapshotsetdeserializemainfunctioncallback-datav8.md#v8startupsnapshotsetdeserializemainfunctioncallback-data配置一个主函数。该函数将被编译并序列化到快照中,但在构建时不会调用。在运行时,主函数将在反序列化的堆上运行,以处理用户输入并生成输出。启动快照脚本的一般约束也适用于用于构建单一可执行应用程序的main脚本,且主脚本可以使用v8.startupSnapshotAPIv8.md#startup-snapshot-apiv8.md#startup-snapshot-api来适应这些约束。请参阅Node.js启动快照支持文档cli.md#--build-snapshotcli.md#--build-snapshot。V8代码缓存支持当配置中的useCodeCache设置为true时,在生成单一可执行准备blob时,Node.js将编译main脚本以生成V8代码缓存。生成的代码缓存将成为准备blob的一部分,并注入到最终的可执行文件中。当单一可执行应用程序启动时,Node.js将使用代码缓存加快编译速度,然后执行脚本,这将改善启动性能。注意:import()在useCodeCache为true时不起作用。注入的主脚本中的API单一可执行应用程序APInode:sea内置模块允许从嵌入到可执行文件中的JavaScript主脚本与单一可执行应用程序进行交互。sea.isSea()返回:{boolean}是否在单一可执行应用程序中运行此脚本。sea.getAsset(key[,encoding])此方法可用于检索在构建时配置到单一可执行应用程序中的资产。当找不到匹配的资产时,会抛出错误。key{string}资产在单一可执行应用程序配置中的键。encoding{string}如果指定,将以字符串形式解码资产。接受TextDecoder支持的任何编码。如果未指定,将返回包含资产副本的ArrayBuffer。返回:{string|ArrayBuffer}sea.getAssetAsBlob(key[,options])类似于sea.getAsset()#seagetassetkey-encoding#seagetassetkey-encoding,但返回结果为Blobhttps://developer.mozilla.org/en-US/docs/Web/API/Blobhttps://developer.mozilla.org/en-US/docs/Web/API/Blob。当找不到匹配的资产时,会抛出错误。key{string}资产在单一可执行应用程序配置中的键。options{Object}type{string}可选的mime类型。返回:{Blob}sea.getRawAsset(key)此方法可用于检索在构建时配置到单一可执行应用程序中的资产。当找不到匹配的资产时,会抛出错误。与sea.getAsset()或sea.getAssetAsBlob()不同,此方法不返回副本。相反,它返回包含在可执行文件中的原始资产。目前,用户应避免写入返回的ArrayBuffer。如果注入的部分未标记为可写或未正确对齐,写入返回的ArrayBuffer可能会导致崩溃。key{string}资产在单一可执行应用程序配置中的键。返回:{string|ArrayBuffer}注入的主脚本中的require(id)注入的主脚本中的require()与非注入模块的require()modules.md#requireidmodules.md#requireid不同。它也没有非注入require()modules.md#requireidmodules.md#requireid的任何属性,除了require.mainmodules.md#accessing-the-main-modulemodules.md#accessing-the-main-module.它只能用于加载内置模块。尝试加载只能在文件系统中找到的模块会抛出错误。用户可以将他们的应用程序打包成独立的JavaScript文件以注入到可执行文件中,这也确保了更确定的依赖关系图。但是,如果仍然需要基于文件的require(),也可以实现:const{createRequire}=require('node:module');require=createRequire(__filename);注入的主脚本中的__filename和module.filename注入的主脚本中的__filename和module.filename的值等于process.execPathprocess.md#processexecpathprocess.md#processexecpath。注入的主脚本中的__dirname注入的主脚本中的__dirname的值等于process.execPathprocess.md#processexecpathprocess.md#processexecpath的目录名。注意事项单一可执行应用程序创建过程旨在创建单一可执行Node.js应用程序的工具必须将准备好的blob内容注入到:如果node二进制文件是PEhttps://en.wikipedia.org/wiki/Portable_Executablehttps://en.wikipedia.org/wiki/Portable_Executable文件,则注入名为NODE_SEA_BLOB的资源如果node二进制文件是Mach-Ohttps://en.wikipedia.org/wiki/Mach-Ohttps://en.wikipedia.org/wiki/Mach-O文件,则注入名为NODE_SEA_BLOB的部分到NODE_SEA段中如果node二进制文件是ELFhttps://en.wikipedia.org/wiki/Executable_and_Linkable_Formathttps://en.wikipedia.org/wiki/Executable_and_Linkable_Format文件,则注入名为NODE_SEA_BLOB的注释在二进制文件中搜索NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2:0fusehttps://www.electronjs.org/docs/latest/tutorial/fuseshttps://www.electronjs.org/docs/latest/tutorial/fuses字符串,并将最后一个字符翻转为1以指示已注入资源。平台支持单一可执行支持在CI上定期测试的以下平台上:WindowsmacOSLinux(所有Node.js支持的发行版支持的架构https://github.com/nodejs/node/blob/main/BUILDING.md#platform-listhttps://github.com/nodejs/node/blob/main/BUILDING.md#platform-list)这是由于缺乏可以用于测试该功能的更好的工具。欢迎对其他资源注入工具/工作流程的建议。请在https://github.com/nodejs/single-executable/discussions发起讨论,帮助我们记录这些信息。

nodejs 327 3月前
NodeJs-Zlib
小卒子

NodeJs-Zlib

Node.js的zlib模块提供了对数据进行压缩和解压缩的功能。该模块支持多种压缩格式,包括Gzip、Deflate、Brotli等,常用于处理HTTP请求和响应的压缩,或者在存储和传输过程中节省带宽和存储空间。Node.js的zlib模块提供了对数据进行压缩和解压缩的功能。该模块支持多种压缩格式,包括Gzip、Deflate、Brotli等,常用于处理HTTP请求和响应的压缩,或者在存储和传输过程中节省带宽和存储空间。以下是zlib模块的详细介绍,包括其所有属性、方法以及使用示例。引入模块constzlib=require('zlib');或者使用ES模块语法:import*aszlibfrom'zlib';可用的压缩方法zlib.gzip:Gzip压缩。zlib.gunzip:Gzip解压缩。zlib.deflate:Deflate压缩。zlib.inflate:Deflate解压缩。zlib.brotliCompress:Brotli压缩。zlib.brotliDecompress:Brotli解压缩.zlib模块提供的类和方法1.zlib.gzipzlib.gzip(buffer[,options],callback)buffer{Buffer|string}要压缩的数据。options{Object}可选配置:level{number}压缩级别,范围从0到9。默认为zlib.constants.Z_DEFAULT_COMPRESSION。memLevel{number}内存使用级别,范围从1到9。默认为8。windowBits{number}窗口大小,范围从8到15。默认为15。callback{Function}回调函数,接受两个参数:err和result。err是错误信息,result是压缩后的数据。示例:constzlib=require('zlib');zlib.gzip('HelloWorld',(err,buffer)=>{if(err){console.error('Errorduringgzip:',err);return;}console.log('Gzippeddata:',buffer);});2.zlib.gunzipzlib.gunzip(buffer[,options],callback)buffer{Buffer|string}要解压缩的数据。options{Object}可选配置,与zlib.gzip的选项类似。callback{Function}回调函数,接受两个参数:err和result。err是错误信息,result是解压缩后的数据。示例:constzlib=require('zlib');zlib.gunzip(gzippedBuffer,(err,buffer)=>{if(err){console.error('Errorduringgunzip:',err);return;}console.log('Gunzipresult:',buffer.toString());});3.zlib.deflatezlib.deflate(buffer[,options],callback)buffer{Buffer|string}要压缩的数据。options{Object}可选配置,与zlib.gzip的选项类似。callback{Function}回调函数,接受两个参数:err和result。err是错误信息,result是压缩后的数据。示例:constzlib=require('zlib');zlib.deflate('HelloWorld',(err,buffer)=>{if(err){console.error('Errorduringdeflate:',err);return;}console.log('Deflateddata:',buffer);});4.zlib.inflatezlib.inflate(buffer[,options],callback)buffer{Buffer|string}要解压缩的数据。options{Object}可选配置,与zlib.deflate的选项类似。callback{Function}回调函数,接受两个参数:err和result。err是错误信息,result是解压缩后的数据。示例:constzlib=require('zlib');zlib.inflate(deflatedBuffer,(err,buffer)=>{if(err){console.error('Errorduringinflate:',err);return;}console.log('Inflatedresult:',buffer.toString());});5.zlib.brotliCompresszlib.brotliCompress(buffer[,options],callback)buffer{Buffer|string}要压缩的数据。options{Object}可选配置:params{Object}Brotli压缩参数,如quality,lgwin等。callback{Function}回调函数,接受两个参数:err和result。err是错误信息,result是压缩后的数据。示例:constzlib=require('zlib');zlib.brotliCompress('HelloWorld',(err,buffer)=>{if(err){console.error('ErrorduringbrotliCompress:',err);return;}console.log('Brotlicompresseddata:',buffer);});6.zlib.brotliDecompresszlib.brotliDecompress(buffer[,options],callback)buffer{Buffer|string}要解压缩的数据。options{Object}可选配置,与zlib.brotliCompress的选项类似。callback{Function}回调函数,接受两个参数:err和result。err是错误信息,result是解压缩后的数据。示例:constzlib=require('zlib');zlib.brotliDecompress(brotliCompressedBuffer,(err,buffer)=>{if(err){console.error('ErrorduringbrotliDecompress:',err);return;}console.log('Brotlidecompressedresult:',buffer.toString());});流式压缩和解压缩zlib模块还支持流式操作,可以用于处理较大的数据流。以下是一些常用的流式方法。1.zlib.createGzipzlib.createGzip([options])options{Object}可选配置,支持与zlib.gzip相同的选项。示例:constfs=require('fs');constzlib=require('zlib');//创建一个gzip压缩流constgzip=zlib.createGzip();//创建一个读流constinput=fs.createReadStream('input.txt');//创建一个写流constoutput=fs.createWriteStream('input.txt.gz');//将数据流通过gzip压缩流input.pipe(gzip).pipe(output);2.zlib.createGunzipzlib.createGunzip([options])options{Object}可选配置,支持与zlib.gunzip相同的选项。示例:constfs=require('fs');constzlib=require('zlib');//创建一个gunzip解压缩流constgunzip=zlib.createGunzip();//创建一个读流constinput=fs.createReadStream('input.txt.gz');//创建一个写流constoutput=fs.createWriteStream('input.txt');//将数据流通过gunzip解压缩流input.pipe(gunzip).pipe(output);3.zlib.createDeflatezlib.createDeflate([options])options{Object}可选配置,支持与zlib.deflate相同的选项。示例:constfs=require('fs');constzlib=require('zlib');//创建一个deflate压缩流constdeflate=zlib.createDeflate();//创建一个读流constinput=fs.createReadStream('input.txt');//创建一个写流constoutput=fs.createWriteStream('input.txt.deflate');//将数据流通过deflate压缩流input.pipe(deflate).pipe(output);4.zlib.createInflatezlib.createInflate([options])options{Object}可选配置,支持与zlib.inflate相同的选项。示例:constfs=require('fs');constzlib=require('zlib');//创建一个inflate解压缩流constinflate=zlib.createInflate();//创建一个读流constinput=fs.createReadStream('input.txt.deflate');//创建一个写流constoutput=fs.createWriteStream('input.txt');//将数据流通过inflate解压缩流input.pipe(inflate).pipe(output);5.zlib.createBrotliCompress**zlib.createBrotliCompress([options])**options{Object}可选配置,支持与zlib.brotliCompress相同的选项。示例:constfs=require('fs');constzlib=require('zlib');//创建一个Brotli压缩流constbrotliCompress=zlib.createBrotliCompress();//创建一个读流constinput=fs.createReadStream('input.txt');//创建一个写流constoutput=fs.createWriteStream('input.txt.br');//将数据流通过Brotli压缩流input.pipe(brotliCompress).pipe(output);6.zlib.createBrotliDecompresszlib.createBrotliDecompress([options])options{Object}可选配置,支持与zlib.brotliDecompress相同的选项.示例:constfs=require('fs');constzlib=require('zlib');//创建一个Brotli解压缩流constbrotliDecompress=zlib.createBrotliDecompress();//创建一个读流constinput=fs.createReadStream('input.txt.br');//创建一个写流constoutput=fs.createWriteStream('input.txt');//将数据流通过Brotli解压缩流input.pipe(brotliDecompress).pipe(output);常量zlib.constants:包含一些常用的常量。Z_BEST_COMPRESSION{number}最大压缩级别。Z_BEST_SPEED{number}最快压缩速度。Z_DEFAULT_COMPRESSION{number}默认压缩级别。Z_DEFAULT_STRATEGY{number}默认策略。Z_NO_FLUSH{number}不立即刷新。总结Node.js的zlib模块为数据压缩和解压缩提供了全面的支持,包括对Gzip、Deflate和Brotli格式的操作。它支持同步和异步API,可以在需要高效处理数据流时使用。通过流式操作,可以方便地处理大规模的数据,从而提高应用程序的性能。

nodejs 307 3月前
NodeJs Worker threads
小卒子

NodeJs Worker threads

Node.js的worker_threads模块提供了在Node.js环境中创建和管理线程的能力。这使得可以在多个线程中并行执行JavaScript代码,从而提高应用程序的性能,尤其是对于CPU密集型任务。该模块是Node.js内置的,提供了一个与浏览器WebWorkers类似的API。模块引入在Node.js中,你可以通过worker_threads模块来使用线程功能:const{Worker,isMainThread,parentPort,workerData}=require('worker_threads');或者使用ES模块语法:import{Worker,isMainThread,parentPort,workerData}from'worker_threads';主要类和接口Node.jsworker_threads模块主要包括以下几个类和接口:WorkerisMainThreadparentPortworkerDataMessagePort1.WorkerWorker类用于创建新的线程并在其中运行JavaScript代码。每个Worker实例代表一个独立的线程。创建Worker示例:const{Worker}=require('worker_threads');//创建一个新的Worker实例constworker=newWorker('./worker.js',{workerData:{foo:'bar'}});//监听Worker发送的消息worker.on('message',(message)=>{console.log('Receivedmessagefromworker:',message);});//监听Worker错误worker.on('error',(error)=>{console.error('Errorfromworker:',error);});//监听Worker退出worker.on('exit',(code)=>{if(code!==0){console.error(`Workerstoppedwithexitcode${code}`);}});构造函数:newWorker(filename[,options])filename{string}运行Worker的JavaScript文件路径。options{Object}配置选项。支持以下选项:workerData{any}传递给Worker线程的数据。stdout{boolean}默认为true。如果为false,则不在控制台输出Worker的stdout。stderr{boolean}默认为true。如果为false,则不在控制台输出Worker的stderr。execArgv{string[]}启动Worker时传递给Node.js的额外参数。实例方法:postMessage(value[,transferList]):向Worker发送消息。value是要发送的消息,transferList是一个可选的Array,指定要转移的ArrayBuffer和MessagePort对象。terminate():终止Worker线程并清理资源。返回一个Promise,在Worker线程被终止时解析。2.isMainThreadisMainThread是一个布尔值,表示当前代码是否在主线程中。主线程是创建Worker实例的线程。示例:const{isMainThread}=require('worker_threads');if(isMainThread){console.log('Thisisthemainthread');}else{console.log('Thisisaworkerthread');}3.parentPortparentPort是一个MessagePort对象,用于在Worker线程和主线程之间进行消息传递。它只能在Worker线程中访问。示例:const{parentPort}=require('worker_threads');parentPort.postMessage('HellofromWorker');4.workerDataworkerData是一个对象,包含传递给Worker线程的数据。在Worker线程中可以通过worker_threads.workerData访问这些数据。示例:const{workerData}=require('worker_threads');console.log('Workerdata:',workerData);5.MessagePortMessagePort对象用于在不同线程之间传递消息。它提供了以下方法和事件:方法:postMessage(value[,transferList]):向对端发送消息。value是要发送的消息,transferList是一个可选的Array,指定要转移的ArrayBuffer和MessagePort对象。事件:message:当接收到消息时触发。事件处理程序接收到一个MessageEvent对象,其中包含接收到的消息。示例:完整的Worker使用示例worker.jsconst{parentPort,workerData}=require('worker_threads');//处理传入的消息parentPort.on('message',(message)=>{console.log('Receivedmessagefrommainthread:',message);//使用workerDataconsole.log('Workerdata:',workerData);//发送消息到主线程parentPort.postMessage('Hellofromworker');});main.jsconst{Worker}=require('worker_threads');//创建一个新的Worker实例constworker=newWorker('./worker.js',{workerData:{foo:'bar'}});//监听Worker发送的消息worker.on('message',(message)=>{console.log('Receivedmessagefromworker:',message);});//发送消息到Workerworker.postMessage('Hellofrommainthread');//处理Worker错误worker.on('error',(error)=>{console.error('Errorfromworker:',error);});//处理Worker退出worker.on('exit',(code)=>{if(code!==0){console.error(`Workerstoppedwithexitcode${code}`);}});总结Node.js的worker_threads模块提供了强大的多线程功能,使得开发者可以在Node.js环境中并行执行JavaScript代码。通过Worker类、isMainThread属性、parentPort对象、workerData和MessagePort对象,可以高效地创建和管理线程,实现并行处理,提升应用程序性能。这个模块为CPU密集型任务提供了有效的解决方案,适用于需要高性能计算的场景。

nodejs 391 3月前
NodeJs Web Streams API
小卒子

NodeJs Web Streams API

Node.js的WebStreamsAPI模块提供了与WebStreams标准一致的流处理功能。它用于处理流数据,支持多种数据流操作,包括读取、写入和转换。WebStreamsAPI是基于流的标准化接口,旨在简化和统一处理流数据的操作。模块引入在Node.js中,你可以通过stream/web模块来访问WebStreamsAPI。使用示例如下:import{ReadableStream,WritableStream,TransformStream}from'stream/web';或在CommonJS模块中:const{ReadableStream,WritableStream,TransformStream}=require('stream/web');主要类和接口Node.jsWebStreamsAPI模块主要包括以下几个类和接口:ReadableStreamWritableStreamTransformStreamReadableStreamDefaultReaderWritableStreamDefaultWriterReadableStreamDefaultControllerWritableStreamDefaultControllerTransformStreamDefaultController1.ReadableStreamReadableStream表示一个从中读取数据的流。它通常用于流式读取数据源。创建ReadableStream示例:constreadableStream=newReadableStream({start(controller){controller.enqueue('Hello');controller.enqueue('World');controller.close();}});方法和属性:getReader():返回一个ReadableStreamDefaultReader对象,该对象可以用来从流中读取数据。tee():返回一个包含两个ReadableStream实例的数组,用于将流分成两个相同的流。2.WritableStreamWritableStream表示一个可以将数据写入的流。它通常用于流式写入数据目标。创建WritableStream示例:constwritableStream=newWritableStream({write(chunk){console.log(`Receivedchunk:${chunk}`);},close(){console.log('Streamclosed');},abort(err){console.error('Streamaborted:',err);}});方法和属性:getWriter():返回一个WritableStreamDefaultWriter对象,该对象可以用来向流中写入数据。abort():取消写入流的操作,并将指定的错误传递给流的abort方法。3.TransformStreamTransformStream是一个变换流,它可以读取数据、处理数据,然后写入处理后的数据。它结合了ReadableStream和WritableStream。创建TransformStream示例:consttransformStream=newTransformStream({transform(chunk,controller){controller.enqueue(chunk.toUpperCase());}});方法和属性:readable:返回一个ReadableStream对象,可以用于从变换流中读取数据。writable:返回一个WritableStream对象,可以用于向变换流中写入数据。4.ReadableStreamDefaultReaderReadableStreamDefaultReader对象用于从ReadableStream中读取数据。方法:read():返回一个Promise,解析为一个对象,其中包含从流中读取的数据或一个done标志。releaseLock():释放对流的读取锁定,允许其他读取器访问该流。5.WritableStreamDefaultWriterWritableStreamDefaultWriter对象用于向WritableStream中写入数据。方法:write(chunk):向流中写入数据。close():关闭流,确保所有数据都已写入。abort(reason):取消写入操作,并将指定的原因传递给流的abort方法。releaseLock():释放对流的写入锁定,允许其他写入器访问该流。6.ReadableStreamDefaultControllerReadableStreamDefaultController对象控制ReadableStream的行为,如数据的排队和流的关闭。方法:enqueue(chunk):将数据块排队到流中。close():关闭流,表明没有更多的数据可供读取。error(e):向流报告错误。7.WritableStreamDefaultControllerWritableStreamDefaultController对象控制WritableStream的行为,如流的处理和错误管理。方法:error(e):向流报告错误。8.TransformStreamDefaultControllerTransformStreamDefaultController对象控制TransformStream的行为,如数据的处理和流的状态。方法:enqueue(chunk):将处理后的数据块排队到输出流中。error(e):向流报告错误。示例1.创建可读流并读取数据constreadableStream=newReadableStream({start(controller){controller.enqueue('Hello');controller.enqueue('World');controller.close();}});constreader=readableStream.getReader();reader.read().then(({done,value})=>{console.log(done,value);//falseHello});2.创建可写流并写入数据constwritableStream=newWritableStream({write(chunk){console.log(`Receivedchunk:${chunk}`);}});constwriter=writableStream.getWriter();writer.write('Hello').then(()=>writer.write('World'));3.创建转换流并进行数据转换consttransformStream=newTransformStream({transform(chunk,controller){controller.enqueue(chunk.toUpperCase());}});constreader=newReadableStream({start(controller){controller.enqueue('Hello');controller.enqueue('World');controller.close();}}).pipeThrough(transformStream);consttransformedReader=reader.getReader();transformedReader.read().then(({done,value})=>{console.log(done,value);//falseHELLO});总结Node.js的WebStreamsAPI模块提供了强大的流处理能力,允许开发者以一致的方式处理数据流,包括读取、写入和转换操作。通过ReadableStream、WritableStream和TransformStream,开发者可以高效地处理流数据,而通过ReadableStreamDefaultReader和WritableStreamDefaultWriter,可以对流进行精细控制。这个API提供了现代化的流操作方式,与浏览器中的WebStreamsAPI保持一致性,使得在不同环境中处理流数据更加方便。

nodejs 345 3月前
NodeJs-Web Crypto API
小卒子

NodeJs-Web Crypto API

Node.js中的WebCryptoAPI模块提供了现代的密码学功能,允许开发者使用加密、解密、签名、验证、哈希等功能。该模块基于WebCryptographyAPI标准,因此提供的API与浏览器环境中的类似,具有一致的使用体验。模块引入在Node.js中,你可以通过crypto.webcrypto来访问WebCryptoAPI。使用示例如下:const{webcrypto}=require('crypto');主要属性和方法Node.js的WebCryptoAPI模块包括以下几个主要部分:SubtleCryptoCryptoKeyKeyAlgorithmSupportedAlgorithms随机数生成(getRandomValues)WebCryptoAPI的实际使用示例1.SubtleCryptoSubtleCrypto对象是WebCryptoAPI的核心部分,提供了加密、解密、签名、验证、哈希、密钥生成和导入/导出的功能。可以通过crypto.webcrypto.subtle来访问:constsubtle=webcrypto.subtle;常用方法:encrypt():使用指定的加密算法对数据进行加密。decrypt():使用指定的加密算法对密文进行解密。sign():使用密钥对数据进行签名。verify():验证签名的有效性。digest():计算数据的哈希值。generateKey():生成加密密钥。deriveKey():从基础密钥派生新的密钥。deriveBits():从基础密钥派生位数据。importKey():导入现有密钥材料,生成CryptoKey对象。exportKey():导出密钥材料。wrapKey():使用密钥对另一个密钥进行加密。unwrapKey():解密加密的密钥。2.CryptoKeyCryptoKey对象代表了在WebCryptoAPI中使用的密钥。所有加密操作都依赖于这些密钥对象。CryptoKey可以是对称密钥或非对称密钥对的组成部分(如RSA密钥对中的公钥或私钥)。CryptoKey的常用属性:type:指示密钥是对称密钥(secret)还是非对称密钥对中的公钥(public)或私钥(private)。extractable:指示密钥是否可以导出。algorithm:密钥的算法。usages:密钥的用途,可以是encrypt,decrypt,sign,verify,deriveKey,deriveBits,wrapKey,unwrapKey等。示例://生成AES-GCM对称密钥subtle.generateKey({name:"AES-GCM",length:256,},true,//密钥是否可导出["encrypt","decrypt"]).then(key=>{console.log(key);});3.KeyAlgorithmKeyAlgorithm对象定义了CryptoKey使用的加密算法,具体包括以下几种:AES-GCM:一种支持认证的对称加密算法。AES-CBC:对称加密算法。HMAC:一种基于密钥的哈希消息认证码。RSA-OAEP:使用OptimalAsymmetricEncryptionPadding的非对称加密算法。RSA-PSS:基于ProbabilisticSignatureScheme的非对称签名算法。ECDSA:基于椭圆曲线的数字签名算法。ECDH:基于椭圆曲线的密钥协商算法。不同算法有各自的参数设置,具体取决于算法的类型。4.SupportedAlgorithmsNode.jsWebCryptoAPI支持的主要算法如下:对称加密算法:AES-GCMAES-CBCAES-CTRAES-KW(密钥包裹算法)非对称加密算法:RSA-OAEPRSA-PSS(签名验证)密钥协商算法:ECDH哈希算法:SHA-1SHA-256SHA-384SHA-512消息认证码:HMAC5.getRandomValues()getRandomValues()是一种用于生成随机数的安全方法。它可以生成加密强度的随机数,适用于生成密钥材料或其他密码学相关的数据。使用示例:constarray=newUint8Array(16);webcrypto.getRandomValues(array);console.log(array);在此示例中,getRandomValues会生成一个长度为16的随机字节数组。6.实际使用示例1.数据加密和解密以下是如何使用AES-GCM对称加密算法来加密和解密数据的示例:asyncfunctionencryptData(data,key){constiv=webcrypto.getRandomValues(newUint8Array(12));//初始化向量constencrypted=awaitsubtle.encrypt({name:"AES-GCM",iv:iv,},key,data);return{encrypted,iv};}asyncfunctiondecryptData(encrypted,key,iv){constdecrypted=awaitsubtle.decrypt({name:"AES-GCM",iv:iv,},key,encrypted);returndecrypted;}(async()=>{constkey=awaitsubtle.generateKey({name:"AES-GCM",length:256,},true,["encrypt","decrypt"]);constdata=newTextEncoder().encode("HelloWorld");const{encrypted,iv}=awaitencryptData(data,key);constdecrypted=awaitdecryptData(encrypted,key,iv);console.log(newTextDecoder().decode(decrypted));})();2.哈希数据下面是使用SHA-256算法对数据进行哈希的示例:asyncfunctionhashData(data){consthash=awaitsubtle.digest("SHA-256",data);returnhash;}(async()=>{constdata=newTextEncoder().encode("HelloWorld");consthash=awaithashData(data);console.log(Buffer.from(hash).toString('hex'));})();3.生成和验证数字签名asyncfunctiongenerateKeyPair(){returnawaitsubtle.generateKey({name:"ECDSA",namedCurve:"P-256",//可选"P-384","P-521"},true,["sign","verify"]);}asyncfunctionsignData(data,privateKey){returnawaitsubtle.sign({name:"ECDSA",hash:"SHA-256",},privateKey,data);}asyncfunctionverifySignature(data,signature,publicKey){returnawaitsubtle.verify({name:"ECDSA",hash:"SHA-256",},publicKey,signature,data);}(async()=>{const{publicKey,privateKey}=awaitgenerateKeyPair();constdata=newTextEncoder().encode("HelloWorld");constsignature=awaitsignData(data,privateKey);constisValid=awaitverifySignature(data,signature,publicKey);console.log("Signaturevalid:",isValid);})();总结Node.js的WebCryptoAPI模块提供了强大的现代密码学支持,包括对称加密、非对称加密、哈希、签名验证、密钥派生等功能。通过SubtleCryptoAPI,开发者能够实现安全的数据加密、解密、哈希和签名功能,同时保持与浏览器端API的一致性。这为构建安全应用程序和实现跨平台的密码学操作提供了便捷的解决方案。

nodejs 427 3月前
NodeJs-WASI
小卒子

NodeJs-WASI

Node.js的wasi模块提供了一种在Node.js环境中使用WebAssemblySystemInterface(WASI)的方式。WASI是一种标准化的WebAssembly模块接口,允许在无操作系统环境(如WebAssembly运行时)中运行程序,并提供类似于文件系统、环境变量等基本操作系统功能。以下是wasi模块的详细介绍,包括其属性、方法和使用示例,涵盖文档的主要内容。1.引入wasi模块const{WASI}=require('wasi');constfs=require('fs');constpath=require('path');2.WASI类WASI类是这个模块的核心,用于与WASI实例进行交互。通过创建WASI实例,你可以提供配置选项,并为WebAssembly模块创建一个环境。构造函数:newWASI(options)options:一个可选对象,用于配置WASI实例。常见的属性包括:args:传递给WASI实例的命令行参数(数组)。env:提供给WASI模块的环境变量(对象)。preopens:文件系统路径的映射(对象),允许WASI访问特定的主机文件系统目录。returnOnExit:如果设置为true,wasi.start()调用会在程序退出时返回,而不是让Node.js进程退出。stderr,stdin,stdout:用于输入/输出流的自定义文件描述符。示例:constwasi=newWASI({args:process.argv,env:process.env,preopens:{'/sandbox':'./sandbox'}});在此示例中,preopens将主机的./sandbox目录映射到WASI实例中的/sandbox。3.wasi.start(instance)wasi.start()方法用于启动一个WebAssembly实例。它接受一个已编译的WebAssembly实例,并在这个实例上运行。instance:WebAssembly实例,由WebAssembly模块生成。示例:const{WASI}=require('wasi');constfs=require('fs');constpath=require('path');constwasi=newWASI();constwasmPath=path.join(__dirname,'example.wasm');constwasmBytes=fs.readFileSync(wasmPath);(async()=>{constwasmModule=awaitWebAssembly.compile(wasmBytes);constinstance=awaitWebAssembly.instantiate(wasmModule,{wasi_snapshot_preview1:wasi.wasiImport});wasi.start(instance);})();wasi.start()启动WebAssembly实例并运行导出的_start函数(如果存在)。这是WebAssembly程序的入口点。4.wasi.initialize(instance)与wasi.start()类似,wasi.initialize()仅初始化WebAssembly实例的WASI环境,而不执行它。这对一些只需初始化而不立即执行的WebAssembly模块很有用。instance:WebAssembly实例。示例:const{WASI}=require('wasi');constfs=require('fs');constpath=require('path');constwasi=newWASI();constwasmPath=path.join(__dirname,'example.wasm');constwasmBytes=fs.readFileSync(wasmPath);(async()=>{constwasmModule=awaitWebAssembly.compile(wasmBytes);constinstance=awaitWebAssembly.instantiate(wasmModule,{wasi_snapshot_preview1:wasi.wasiImport});wasi.initialize(instance);})();5.wasi.wasiImport属性wasi.wasiImport是WASI模块导入到WebAssembly实例中的对象。这个对象包含了与WASI相关的所有功能,例如与文件系统、时间、随机数生成等操作相关的API。你在创建WebAssembly实例时,需要将wasi.wasiImport作为导入提供给WebAssembly实例。示例:const{WASI}=require('wasi');constfs=require('fs');constpath=require('path');constwasi=newWASI();constwasmPath=path.join(__dirname,'example.wasm');constwasmBytes=fs.readFileSync(wasmPath);(async()=>{constwasmModule=awaitWebAssembly.compile(wasmBytes);constinstance=awaitWebAssembly.instantiate(wasmModule,{wasi_snapshot_preview1:wasi.wasiImport//这里引入wasiImport});wasi.start(instance);})();在这个例子中,我们将wasi.wasiImport作为wasi_snapshot_preview1模块的导入,传递给WebAssembly实例。6.文件系统的预打开(Preopen)机制WASI允许通过preopens选项将主机文件系统的一部分公开给WebAssembly实例。这种机制允许WebAssembly代码在被限制的文件系统内进行文件操作。在WASI中,你需要映射文件系统路径来打开文件或目录。映射的路径只能是wasi模块配置中preopens中定义的目录。示例:constwasi=newWASI({preopens:{'/sandbox':'./sandbox'//将主机文件系统的./sandbox目录映射到WASI实例中的/sandbox}});在WASI中,WebAssembly代码可以访问/sandbox目录中的文件,并进行读写操作。7.使用环境变量env选项允许你为WASI模块提供环境变量。这些变量可以在WebAssembly代码中访问。示例:constwasi=newWASI({env:{'MY_VARIABLE':'some_value'}});console.log(process.env.MY_VARIABLE);//输出:some_value8.自定义输入/输出流WASI模块通常需要使用标准输入(stdin)、标准输出(stdout)和标准错误(stderr)流进行输入和输出。你可以在WASI实例中通过stdin,stdout和stderr选项自定义这些流。示例:constwasi=newWASI({stdin:process.stdin,stdout:process.stdout,stderr:process.stderr});你可以将这些流重新定向到文件或其他Node.js流对象,以控制WebAssembly实例的I/O操作。9.WASI返回码当WASI程序执行结束时,wasi.start()返回的WASI退出码指示程序的执行结果。你可以根据退出码判断程序的成功或失败。0:成功。其他值:错误码。示例:try{wasi.start(instance);}catch(e){console.error(`WASI程序退出码:${e}`);}10.错误处理当WASI实例的执行中发生错误时,可以捕获并处理这些错误。例如,如果WebAssembly模块访问了它不允许的文件系统路径或发生了其他异常,则会抛出错误。示例:try{wasi.start(instance);}catch(error){console.error('WASIError:',error);}总结Node.js的wasi模块提供了一个强大的机制,可以在Node.js中运行WebAssembly程序,并利用标准的WebAssemblySystemInterface(WASI)。通过WASI类、wasiImport、文件系统预打开机制、自定义I/O流和环境变量,开发者可以轻松地在Node.js环境中执行WebAssembly代码,并与底层的文件系统和输入输出进行交互。

nodejs 315 3月前
NodeJs-VM
小卒子

NodeJs-VM

Node.js的vm模块为执行JavaScript代码提供了独立的沙箱环境,它允许将JavaScript代码放入隔离的虚拟机(VM)上下文中运行,并提供与主上下文的有限交互。这对于需要安全地运行不信任的代码或需要创建隔离环境的场景非常有用。以下是vm模块的属性和方法的详细说明,涵盖该模块的所有主要功能和用法。1.引入vm模块constvm=require('vm');2.vm.Script类vm.Script类表示一个预编译的JavaScript脚本,可以在多个上下文中反复执行。构造函数:newvm.Script(code[,options])code:要编译的JavaScript代码。options:可选项。可以配置的属性包括:filename:脚本的文件名(用于错误堆栈跟踪)。lineOffset:错误报告的行偏移量。columnOffset:错误报告的列偏移量。displayErrors:如果为true,则会在错误时显示更具描述性的错误消息。示例:constvm=require('vm');constscript=newvm.Script('constx=42;x+1;');constresult=script.runInThisContext();console.log(result);//输出:433.vm.createContext(sandbox)vm.createContext()创建一个隔离的沙箱上下文。沙箱是一个JavaScript对象,所有脚本在这个上下文中执行时都可以访问该对象中的属性。示例:constvm=require('vm');constsandbox={x:2};vm.createContext(sandbox);constcode='x+=40;vary=17;';vm.runInContext(code,sandbox);console.log(sandbox);//输出:{x:42,y:17}vm.createContext()将sandbox转换为一个可以运行代码的安全环境。在这个例子中,代码x+=40;和vary=17;在沙箱中执行,并修改了沙箱中的x值,同时添加了新的y值。4.vm.runInContext(code,context[,options])vm.runInContext()在指定的上下文中执行代码。这种方式允许在隔离的沙箱中运行JavaScript代码,并且代码对主进程的上下文没有直接影响。code:要执行的JavaScript代码。context:通过vm.createContext()创建的上下文。options:可选配置,类似于vm.Script的选项。示例:constvm=require('vm');constsandbox={a:1,b:2};vm.createContext(sandbox);vm.runInContext('a+=5;b*=3;',sandbox);console.log(sandbox);//输出:{a:6,b:6}5.vm.runInNewContext(code[,sandbox][,options])vm.runInNewContext()在一个全新的上下文中执行代码,该上下文与当前的环境完全隔离。可以传递一个沙箱对象来作为上下文的全局对象。示例:constvm=require('vm');constresult=vm.runInNewContext('x+y',{x:10,y:5});console.log(result);//输出:156.vm.runInThisContext(code[,options])vm.runInThisContext()在当前的全局上下文中运行代码,类似于直接在当前上下文中执行代码,但代码在一个隔离的环境中运行。它允许执行代码,但不会对当前上下文做出任何全局更改。示例:constvm=require('vm');constresult=vm.runInThisContext('varz=5;z*2;');console.log(result);//输出:10//`z`不会被定义在当前上下文中console.log(typeofz);//输出:'undefined'7.vm.isContext(sandbox)vm.isContext()检查某个对象是否是通过vm.createContext()创建的上下文对象。示例:constvm=require('vm');constsandbox={x:1};console.log(vm.isContext(sandbox));//输出:falsevm.createContext(sandbox);console.log(vm.isContext(sandbox));//输出:true8.vm.measureMemory([context])vm.measureMemory()返回与V8引擎内存使用情况相关的指标。这个函数返回一个Promise,可以报告当前上下文或特定上下文的内存使用情况。此API是实验性的。context:可选参数,指定要测量的上下文。如果未提供,则测量当前的上下文。示例:constvm=require('vm');vm.measureMemory().then((memoryUsage)=>{console.log(memoryUsage);});输出的结果包含几个字段,如total,used,external,arrayBuffers,这些字段提供了内存的总大小、已使用大小等信息。9.vm.Script.prototype.runInNewContext([sandbox][,options])这是vm.Script实例的一个方法,用于在新创建的上下文中运行预编译的脚本。示例:constvm=require('vm');constscript=newvm.Script('x=10');constsandbox={};script.runInNewContext(sandbox);console.log(sandbox.x);//输出:1010.vm.Script.prototype.runInContext(context[,options])在指定的上下文中运行预编译的脚本。示例:constvm=require('vm');constscript=newvm.Script('x=5');constsandbox={x:1};vm.createContext(sandbox);script.runInContext(sandbox);console.log(sandbox.x);//输出:511.vm.Script.prototype.runInThisContext([options])在当前上下文中执行预编译的脚本。这个方法在概念上类似于vm.runInThisContext(),但它运行的是预编译的脚本。示例:constvm=require('vm');constscript=newvm.Script('vary=20;');script.runInThisContext();console.log(typeofy);//输出:'undefined'12.vm.compileFunction(functionBody,params,options)vm.compileFunction()用于编译一个函数,在独立的上下文中执行函数体。它允许指定函数的参数以及执行的环境(沙箱)。functionBody:要编译的函数体(字符串)。params:函数参数列表(数组)。options:可选项,支持指定上下文、文件名、行/列偏移等。示例:constvm=require('vm');constfn=vm.compileFunction('returna+b;',['a','b']);console.log(fn(10,20));//输出:30总结Node.js的vm模块提供了一个强大的工具,用于在隔离环境中执行JavaScript代码。通过vm.Script,vm.createContext(),vm.runInContext()等方法,开发者可以在虚拟机沙箱中运行代码,有效提高代码的安全性和灵活性。

nodejs 345 3月前
NodeJs-V8
小卒子

NodeJs-V8

Node.js的v8模块提供了与V8引擎相关的接口,允许开发者直接访问V8引擎的内部操作及数据结构。V8是Chrome和Node.js中使用的JavaScript引擎,该模块提供了一些用于内存管理、堆快照以及性能调试的工具。以下是Node.jsv8模块的详细说明,涵盖属性、方法及用法。1.引入v8模块要使用v8模块,首先需要通过require引入该模块:constv8=require('v8');2.v8.getHeapStatistics()v8.getHeapStatistics()返回V8内存管理系统的一些统计信息,如堆总大小、已使用的堆大小等。示例:constv8=require('v8');console.log(v8.getHeapStatistics());输出结果包含以下字段:total_heap_size:堆的总大小(以字节为单位)。total_heap_size_executable:可执行堆大小(字节)。total_physical_size:物理分配给V8堆的大小(字节)。used_heap_size:已使用的堆大小(字节)。heap_size_limit:当前堆的大小上限(字节)。malloced_memory:通过malloc()分配的内存大小(字节)。peak_malloced_memory:通过malloc()分配的峰值内存大小(字节)。does_zap_garbage:是否使用垃圾值填充已释放的内存(用于调试)。3.v8.getHeapSpaceStatistics()v8.getHeapSpaceStatistics()返回关于V8堆空间的信息。堆空间是内存中的区域,用于存储对象和数据结构。示例:constv8=require('v8');constheapSpaceStats=v8.getHeapSpaceStatistics();heapSpaceStats.forEach((space)=>{console.log(space);});输出信息包含以下字段:space_name:堆空间的名称(如新生代、老生代等)。space_size:堆空间的总大小。space_used_size:已使用的堆空间大小。space_available_size:可用的堆空间大小。physical_space_size:物理分配给该空间的大小。4.v8.setFlagsFromString()v8.setFlagsFromString(flags)允许在运行时向V8引擎传递命令行标志。可以启用某些V8功能或调试模式。示例:constv8=require('v8');//启用V8的跟踪GC选项v8.setFlagsFromString('--trace_gc');注意:并非所有标志都可以动态设置,某些标志需要在进程启动时设置。5.v8.serialize()与v8.deserialize()v8.serialize()用于将JavaScript值序列化为Buffer,而v8.deserialize()用于反序列化Buffer,恢复原始的JavaScript对象。示例:constv8=require('v8');constobj={name:'Alice',age:30};constbuffer=v8.serialize(obj);console.log(buffer);//输出:<Buffer...>constdeserializedObj=v8.deserialize(buffer);console.log(deserializedObj);//输出:{name:'Alice',age:30}这对于在不同进程之间传输数据或在文件中保存数据很有用。6.v8.takeHeapSnapshot()v8.takeHeapSnapshot()可以获取当前V8堆的快照,并将其写入到指定的文件流中。这个堆快照对于分析内存泄漏或性能调优非常有帮助。示例:constv8=require('v8');constfs=require('fs');constfile=fs.createWriteStream('./heap-snapshot.heapsnapshot');v8.writeHeapSnapshot(file);生成的.heapsnapshot文件可以通过ChromeDevTools或其他工具进行分析。7.v8.cachedDataVersionTag()v8.cachedDataVersionTag()返回当前V8版本的缓存数据版本标记。这个标记在不同版本的V8引擎之间可能不同,用于标识不同版本的代码缓存。示例:constv8=require('v8');console.log(v8.cachedDataVersionTag());此方法对于代码缓存的兼容性检查很有用。8.v8.getHeapCodeStatistics()v8.getHeapCodeStatistics()返回有关V8堆中代码和编译代码的统计信息。示例:constv8=require('v8');console.log(v8.getHeapCodeStatistics());输出的结果包括以下字段:code_and_metadata_size:代码和元数据的大小。bytecode_and_metadata_size:字节码和元数据的大小。external_script_source_size:外部脚本源的大小。9.v8.writeHeapSnapshot()v8.writeHeapSnapshot()将当前堆的快照写入指定文件。该方法类似于v8.takeHeapSnapshot(),用于生成内存快照文件。示例:constv8=require('v8');v8.writeHeapSnapshot('./snapshot.heapsnapshot');生成的快照可以用于内存分析工具中。10.V8堆管理和内存调优通过v8模块,开发者可以更加细致地监控和调优Node.js应用程序的内存使用情况。这对于分析应用的内存泄漏或理解垃圾回收的行为非常有用。配合v8提供的堆统计和快照功能,可以在应用的不同运行阶段获取详细的内存使用情况。示例:constv8=require('v8');//获取当前堆的统计数据constheapStats=v8.getHeapStatistics();console.log('Heapsizelimit:',heapStats.heap_size_limit);console.log('Usedheapsize:',heapStats.used_heap_size);总结Node.js的v8模块提供了一些直接与V8引擎交互的工具,可以帮助开发者深入理解和优化JavaScript应用程序的性能,特别是在内存使用和垃圾回收方面。常用的功能包括获取堆统计信息、序列化/反序列化对象、生成堆快照等。通过这些工具,开发者可以更好地进行内存调试和性能分析,尤其是在大型或复杂的Node.js应用程序中。

nodejs 300 3月前
NodeJs-Utilities
小卒子

NodeJs-Utilities

Node.js的util模块提供了许多实用的函数和工具,帮助开发者处理调试、继承、类型检查等常见的任务。util模块特别适合进行日志记录、格式化输出以及处理异步操作等。以下是该模块的所有属性和方法的详细介绍及使用示例,涵盖了模块的各个方面。1.引入util模块首先,通过require引入util模块:constutil=require('util');2.util.format()util.format(format,[...args])方法用于字符串格式化,它类似于printf这样的函数。%s:字符串%d:数字(包括整数和浮点数)%i:整数%f:浮点数%j:JSON%%:百分号(不会被替换)示例:constutil=require('util');conststr=util.format('Mynameis%s,andIam%dyearsold.','Alice',30);console.log(str);//输出:MynameisAlice,andIam30yearsold.3.util.inspect()util.inspect(object,[options])方法用于将任意对象转为字符串,适合用于调试和日志记录。它会对对象进行递归输出,提供对嵌套对象的完整查看。showHidden:默认false,显示隐藏属性。depth:递归显示对象的层级深度,默认值为2。colors:输出是否带颜色,默认值为false。customInspect:如果true,则对象的inspect()方法会被调用,默认值为true。示例:constutil=require('util');constobj={a:5,b:{c:10}};console.log(util.inspect(obj,{showHidden:false,depth:null,colors:true}));4.util.typesutil.types提供了一系列用于类型检查的工具函数,类似于typeof和instanceof,但更为准确。常用方法:util.types.isDate(value):检查对象是否是Date。util.types.isRegExp(value):检查对象是否是正则表达式。util.types.isSet(value):检查对象是否是Set。util.types.isMap(value):检查对象是否是Map。示例:constutil=require('util');console.log(util.types.isDate(newDate()));//trueconsole.log(util.types.isRegExp(/abc/));//trueconsole.log(util.types.isMap(newMap()));//trueconsole.log(util.types.isSet(newSet()));//true5.util.callbackify()util.callbackify()将返回一个把async函数转换为遵循错误优先风格的回调函数的函数。返回的函数会将异步函数的结果传递给回调。示例:constutil=require('util');asyncfunctionfoo(){return'Hello';}constcallbackFoo=util.callbackify(foo);callbackFoo((err,result)=>{if(err)throwerr;console.log(result);//输出:'Hello'});6.util.promisify()util.promisify()将传统的回调风格函数(即最后一个参数是回调函数的函数)转换为返回Promise的函数。示例:constutil=require('util');constfs=require('fs');constreadFile=util.promisify(fs.readFile);readFile('./example.txt','utf8').then(data=>console.log(data)).catch(err=>console.error(err));7.util.deprecate()util.deprecate()方法用于将某个函数标记为废弃。调用被废弃的函数时,会显示一条警告信息。适用于标记不推荐使用的API。示例:constutil=require('util');constoldFunc=util.deprecate(()=>{console.log('Thisfunctionisdeprecated');},'oldFunc()isdeprecatedandwillberemovedinfutureversions');oldFunc();//调用时会输出警告信息8.util.inherits()util.inherits(constructor,superConstructor)是用于对象原型继承的工具函数,帮助简化构造函数的继承。注意:在ES6中推荐使用class和extends。示例:constutil=require('util');functionPerson(){this.name='Alice';}Person.prototype.sayHello=function(){console.log(`Hello,mynameis${this.name}`);};functionStudent(){Person.call(this);this.age=20;}util.inherits(Student,Person);conststudent=newStudent();student.sayHello();//输出:Hello,mynameisAlice9.util.TextEncoder和util.TextDecoderTextEncoder和TextDecoder是用于处理文本编码和解码的工具,可以将字符串编码为Uint8Array,或从字节数组解码为字符串。示例:const{TextEncoder,TextDecoder}=require('util');constencoder=newTextEncoder();constdecoder=newTextDecoder();constencoded=encoder.encode('Hello,world!');console.log(encoded);//输出:Uint8Arrayconstdecoded=decoder.decode(encoded);console.log(decoded);//输出:'Hello,world!'10.util.log()util.log()是一个简单的日志记录函数,输出信息并附带时间戳。示例:constutil=require('util');util.log('Serverstarted');//输出:'21Sep10:56:23-Serverstarted'11.util.getSystemErrorName()util.getSystemErrorName()接受一个错误码,返回对应的系统错误名称(如ENOENT,EADDRINUSE等)。示例:constutil=require('util');consterrorName=util.getSystemErrorName(-2);console.log(errorName);//输出:ENOENT12.util.debuglog()util.debuglog()创建一个用于调试的日志函数,该函数仅在特定环境变量被设置时输出日志信息。示例:constutil=require('util');constdebuglog=util.debuglog('myapp');debuglog('Debuggingmessage:%o',{foo:'bar'});要启用日志输出,需要设置环境变量NODE_DEBUG=myapp。13.util.inspect.customutil.inspect.custom是一个用于定制对象的util.inspect()输出的符号。通过实现该属性,可以控制对象在被util.inspect()时的输出行为。示例:constutil=require('util');classMyClass{constructor(){this.foo='bar';}[util.inspect.custom](){return'MyClassinstance';}}constmyInstance=newMyClass();console.log(util.inspect(myInstance));//输出:MyClassinstance14.util.promisify.customutil.promisify.custom是一个符号,用于定义promisify方法的自定义行为。通过实现该属性,函数可以自定义如何被util.promisify()转换。示例:constutil=require('util');functioncustomAsyncFunction(callback){callback(null,'result');}customAsyncFunction[util.promisify.custom]=()=>{returnPromise.resolve('customresult');};constpromisified=util.promisify(customAsyncFunction);promisified().then(result=>{console.log(result);//输出:'customresult'});总结Node.js的util模块为开发者提供了一系列实用工具,简化了开发过程中常见任务的处理。它支持字符串格式化、对象的调试输出、类型检查、异步函数的处理等功能,非常适合在Node.js环境中进行快速开发和调试。

nodejs 266 3月前
NodeJs-URL
小卒子

NodeJs-URL

Node.js的url模块提供了用于解析URL(统一资源定位符)、格式化URL、解析查询字符串等的工具。它支持各种协议(如HTTP、HTTPS、FTP等),并且可以将URL字符串解析为其组成部分。以下是url模块的相关属性、方法及其详尽的使用说明,涵盖了模块的各个方面。1.引入url模块首先,通过require引入url模块:consturl=require('url');自Node.jsv7以后,还可以使用WHATWGURL标准,这种方式对URL解析的处理方式更接近浏览器标准。以下会分别介绍两种API。2.URL解析url.parse()是Node.js提供的传统URL解析方法,用于将URL字符串解析为URL对象。2.1url.parse(urlString,[parseQueryString],[slashesDenoteHost])urlString:要解析的URL字符串。parseQueryString:如果为true,则会将查询字符串解析为对象。默认为false。slashesDenoteHost:如果为true,即使没有协议前缀,也会将双斜杠后的部分解析为host。默认为false。示例:consturl=require('url');constparsedUrl=url.parse('https://example.com:8080/path?name=abc&age=30#hash',true);console.log(parsedUrl);输出结果:Url{protocol:'https:',slashes:true,auth:null,host:'example.com:8080',port:'8080',hostname:'example.com',hash:'#hash',search:'?name=abc&age=30',query:{name:'abc',age:'30'},//如果第二个参数为true,则query会被解析为对象pathname:'/path',path:'/path?name=abc&age=30',href:'https://example.com:8080/path?name=abc&age=30#hash'}说明:protocol:协议,如http:,https:。slashes:如果协议后有双斜杠(//),该值为true。host:主机名与端口号(如果有)。port:端口号。hostname:主机名。hash:URL中的片段标识符(#之后的部分)。search:查询字符串(包括问号?)。query:解析后的查询参数对象或字符串(取决于parseQueryString参数)。pathname:URL的路径部分。path:路径与查询字符串的组合。href:完整的URL字符串。2.2URL.parse()示例-slashesDenoteHost参数如果没有协议时,也可以将双斜杠后的部分解析为host:constparsedUrl=url.parse('//example.com/path',false,true);console.log(parsedUrl.host);//输出:'example.com'3.URL解析的新API(WHATWGURL)自Node.jsv7开始,Node.js提供了一个符合WHATWG标准的URL类,这种方式与现代浏览器的行为更加一致。3.1newURL(input,[base])input:要解析的URL字符串。base:可选的基准URL。如果input是相对URL,则需要提供基准URL。示例:const{URL}=require('url');constmyUrl=newURL('https://example.com:8080/path?name=abc&age=30#hash');console.log(myUrl);输出结果:URL{href:'https://example.com:8080/path?name=abc&age=30#hash',origin:'https://example.com:8080',protocol:'https:',username:'',password:'',host:'example.com:8080',hostname:'example.com',port:'8080',pathname:'/path',search:'?name=abc&age=30',searchParams:URLSearchParams{'name'=>'abc','age'=>'30'},hash:'#hash'}3.2相对URL和基准URL如果input是相对URL,必须提供base作为基准:const{URL}=require('url');constmyUrl=newURL('/path','https://example.com');console.log(myUrl.href);//输出:'https://example.com/path'4.URL格式化4.1url.format(urlObject)将URL对象或WHATWGURL实例格式化为字符串。consturl=require('url');consturlObject={protocol:'https:',host:'example.com',pathname:'/path',query:{name:'abc',age:30}};constformattedUrl=url.format(urlObject);console.log(formattedUrl);//输出:'https://example.com/path?name=abc&age=30'4.2WHATWGURL格式化WHATWGURL实例的toString()和href属性也可以格式化URL:const{URL}=require('url');constmyUrl=newURL('https://example.com/path?name=abc');console.log(myUrl.href);//输出:'https://example.com/path?name=abc'console.log(myUrl.toString());//输出:'https://example.com/path?name=abc'5.URL查询参数处理5.1url.parse()处理查询字符串如果url.parse()的第二个参数为true,查询字符串会被解析为对象:constparsedUrl=url.parse('https://example.com/path?name=abc&age=30',true);console.log(parsedUrl.query);//输出:{name:'abc',age:'30'}5.2WHATWGURLSearchParams类WHATWGURL标准引入了URLSearchParams类,可以更方便地处理查询参数。创建URLSearchParamsconst{URLSearchParams}=require('url');constparams=newURLSearchParams('name=abc&age=30');console.log(params.get('name'));//输出:'abc'console.log(params.get('age'));//输出:'30'添加、修改和删除参数constparams=newURLSearchParams();params.append('name','abc');params.append('age','30');params.set('age','31');//修改参数params.delete('name');//删除参数console.log(params.toString());//输出:'age=31'5.3searchParams在WHATWGURL中使用WHATWGURL实例自动提供searchParams属性,用于处理查询参数:const{URL}=require('url');constmyUrl=newURL('https://example.com/path?name=abc&age=30');console.log(myUrl.searchParams.get('name'));//输出:'abc'myUrl.searchParams.append('city','NewYork');console.log(myUrl.toString());//输出:'https://example.com/path?name=abc&age=30&city=New+York'6.URL解析中的其他方法6.1url.resolve(from,to)将相对URLto基于from解析为绝对URL。这种方法类似于浏览器中处理相对路径的方法。constresolvedUrl=url.resolve('https://example.com/dir/','sub');console.log(resolvedUrl);//输出:'https://example.com/dir/sub'如果to是绝对路径,它会替换掉from的路径部分:constresolvedUrl=url.resolve('https://example.com/dir/','/other');console.log(resolvedUrl);//输出:'https://example.com/other'7.API的区别与适用场景url.parse()与url.format():适用于传统的URL处理场景,尤其是在Node.jsv7之前使用较多。WHATWGURLAPI:更符合现代Web标准,推荐在Node.jsv10+的项目中使用,提供了更灵活、强大的URL处理方式。url.parse()是Node.js提供的传统方法,它将URL解析为对象,适合处理简单的URL场景。newURL()是WHATWG标准的一部分,它提供了更符合现代浏览器的解析方式,适合处理复杂的、基于标准的URL。总结Node.jsurl模块无论是传统的API还是WHATWG标准API都提供了丰富的功能,能够满足绝大多数场景的需求。在处理URL时,根据需求选择合适的解析方式,并在复杂项目中建议使用WHATWG标准,以保证与浏览器端一致的行为。

nodejs 288 3月前
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 >> 尾页 共 41 页