关于node.js:一款基于Vue3实现的漂亮且功能强大的在线海报设计器

大家好,我是 Java陈序员。 咱们在工作中常常须要设计各种各样的图片,海报、产品图、文章图片、视频/公众号等。 咱们能够抉择应用 PS 来设计图片,然而有时候想疾速实现工作,有没有一款工具反对疾速生成海报呢? 答案是有的,明天给大家介绍一款在线图片(海报)设计器。 关注微信公众号:【Java陈序员】,获取开源我的项目分享、AI副业分享、超200本经典计算机电子书籍等。我的项目介绍poster-design —— 一款丑陋且功能强大的在线海报设计器、图片编辑器、仿稿定设计。 实用于海报生成、电商产品图、文章长图、视频/公众号封面等多种场景。 poster-design 基于 Vue3 + Vite2 + Vuex + ElementPlus 技术栈实现,应用 Puppeteer + Express 生成图片。 poster-design 具备欠缺的根底性能,页面操作丝滑,交互细节丰盛。应用服务端生成图片,反对简略的 AI 抠图工具,可一键去除图片背景。 性能特色: 反对导入 PSD 文件解析成模板、在线导出图片下载。元素拖拽、组合、缩放、层级调整、对齐等操作。图片素材插入、替换、裁剪,图片容器等性能。SVG 素材色彩、透明度编辑,文字花字组合。画布自定义尺寸、滚轮缩放、自适应画布吸附对齐、辅助疏导线、标尺性能。键盘快捷键、右键菜单快捷操作,复制删除等罕用操作。格调二维码编辑,反对单色、突变、自定义 logo 等。图层操作,反对拖拽变更层级。色彩调色板,原生级取色器色彩吸管(Chrome)。我的项目地址: https://github.com/palxiao/poster-design在线体验: https://design.palxp.cn/home性能体验1、多种模板抉择 2、文字图层设计 3、丰盛的素材库 4、多种多样的文字款式 5、图片库 6、工具箱 本地部署1、克隆代码 git clone https://github.com/palxiao/poster-design.git2、装置依赖 cd poster-designnpm run prepared3、启动服务 npm run serve将会同时运行前端界面与图片生成服务(3000端口为前端我的项目,7001端口为图片生成服务)4、浏览器拜访 http://127.0.0.1:3000/ 最初举荐的开源我的项目曾经收录到 GitHub 我的项目,欢送 Star: https://github.com/chenyl8848/great-open-source-project或者拜访网站,进行在线浏览: https://chencoding.top:8090/#/大家的点赞、珍藏和评论都是对作者的反对,如文章对你有帮忙还请点赞转发反对下,谢谢!

March 4, 2024 · 1 min · jiezi

关于node.js:Nodejs-应用集成谷歌生成式AI-Gemini

hello 大家好,我是 superZidan,这篇文章想跟大家聊聊 Node.js 利用集成谷歌生成式AI Gemini ,如果大家遇到任何问题,欢送 分割我 或者间接微信增加 superZidan41  后方高能,干货满满,倡议点赞➕关注➕珍藏; 介绍在过来一年, 生成式 AI 曾经成为技术圈最热门的话题。每个人都是用它来构建我的项目。Google 也领有本人的生成式 AI,叫做 Gemini。 最近,Google 曾经为开发者公布了 Gemini 的 API。它蕴含了一些库和框架,开发者能够将其集成到本人的利用中去。 在本篇文章中,咱们将构建一个简略的 Node.js 利用并将 Google Gemni 集成进来。咱们将通过 Google Gemini SDK 来实现。 让咱们马上开始吧! 什么是 Gemini ? Google Gemini 是 Google 团队开发的一个弱小且多面的 AI 模型。Gemini 不仅仅能够解决文字,还能够了解和解决多种格局比方:代码,音频,图片和视频。这为你的 Node.js 我的项目带来了有限的可能性。 我的项目创立创立 Node.js 我的项目 咱们须要先创立 Node.js 环境来开始咱们的我的项目。所以,让咱们先创立一个 node 我的项目。在终端运行上面的命令 npm init这个将会初始化一个新的 Node.js 我的项目 装置依赖 当初,咱们将装置我的项目必要的依赖 npm install express body-parser @google/generative-ai dotenv这个将会装置以下的依赖包: express: 一个风行的 Node.js Web 利用框架body-parser: 解析申请体的中间件@google/generative-ai: 对接 Gemini 模型能力dotenv: 从 .env 文件加载环境变量设置环境变量 ...

March 1, 2024 · 3 min · jiezi

关于node.js:工具用nvm管理nodejs版本切换真香

前言原因换个nodejs版本比换个媳妇还难,nvm堪称治理nodejs版本神器事件的起因,公司的一些老我的项目须要依赖稳固老版本的nodejs,然而本人的一些我的项目所须要的是更高版本的nodejs,这就会面临频繁切换版本的状况。看到很多共事小伙伴并没有应用nvm进行版本治理,面对切换的苦恼,遂将本狗应用nvm的办法进行分享,彻底辞别nodejs版本切换的困扰。 实例展现A,B两个并行开发我的项目,nodejs依赖版本不统一。A我的项目须要v14.19.1老版本,B我的项目须要v16.15.0新版本,须要随时切换 以后nodejs版本 B我的项目拉取依赖报错#npm下载依赖npm i 应用nvm灵便切换版本#查看nodejs版本node -v#查看已装置所有版本nvm list #切换版本nvm use 16.15.0#查看nodejs版本nvm -v 次要指标实现4大重点1. nvm介绍2. nvm下载3. nvm装置4. nvm常用命令注释前置条件卸载已装置nodejs# 查看是否装置nodejs,展现版本则是已装置node -v 未装置⭕如果没有装置nodejs能够跳过此步骤 已装置❓如何删除已装置的nodejs? 在控制面板中卸载nodejs 删除nodejs装置目录默认在C:\Program Files\nodejs,若没有采纳默认地址则须要找到过后装置时门路 删除.npmrc配置文件默认会在C:\User\用户名 删除可能脱漏的nodejs文件 C:\Program Files (x86)\NodejsC:\Program Files\NodejsC:\Users\用户名\AppData\Roaming\npmC:\Users\用户名\AppData\Roaming\npm-cache查看是否删除胜利 node -v 提醒【不是外部或外部命令,也不是可运行的程序或批处理文件】则为删除胜利逐渐剖析1.nvm介绍nvm是什么?nvm 一个nodejs版本管理工具! nvm全英文也叫node.js version management,是一个nodejs的版本管理工具。nvm和n都是node.js版本管理工具,为了解决node.js各种版本存在不兼容景象能够通过它能够装置和切换不同版本的node.js。 nvm能干嘛?简略的命令下载长期稳固反对版本的 Node.js 简略的命令实现 Node.js 的多个版本之间轻松切换 2.nvm下载官网github地址https://github.com/coreybutler/nvm-windows/releases/tag/1.1.12 3.nvm装置【双击】nvm-setup.exe 【Next】依据磁盘散布自行抉择装置 【Install】无脑装置即可 【配置】nvm环境变量C盘默认装置⭕如果C盘默认装置nodejs能够跳过此步骤 自定义装置【右键】我的电脑=》 属性=》 高级设置=》 环境变量 【新建】零碎变量NVM_HOME,将nvm装置目录配置进去(我的目录是E:\tools\nvm),并设置名称NVM_HOME 编辑【Path】将零碎变量【NVM_HOME】配置到【Path】中 【CMD】测试装置成绩 4.nvm常用命令查看可用nodejs的稳固版本# 查看可用nodejs的稳固版本nvm list available 下载指定node版本# 下载nodejs 20.9.0nvm install 20.9.0 ...

February 27, 2024 · 1 min · jiezi

关于node.js:vue中引入外部commandjs语法文件编译报错

node打包运行谬误总结:从零开始搭建node我的项目,并反对es6和commonjs我遇到的问题是build之后报错,报错如下解决形式是在babel.config.js中增加sourceType: 'unambiguous', 相干链接https://blog.csdn.net/qq_33202546/article/details/122132326

February 26, 2024 · 1 min · jiezi

关于node.js:短小精悍的npm入门级保姆教程一篇包会

npm是什么?npm是一个弱小的包管理工具,它使开发人员可能轻松地装置、更新和治理我的项目依赖的包。通过初始化一个package.json 文件,咱们能够形容你的我的项目并记录其依赖关系。应用npm install命令,咱们能够装置和治理包。应用npm publish命令,咱们能够公布本人的包(因为日常很少波及公布本人的包,这里就不总结了)。无论是在开发过程中还是在分享你的包时,npm都提供了丰盛的性能和命令来满足你的需要。 然而在日常搜寻网上文章时,发现网上的文章总结的一大堆,而这个npm很多时候对于咱们来说就是一个工具,并不波及如许浅近的学习,所以,我这里的这篇文章就进行高度概括的总结,力争通过这一篇文章让大家会用npm。 npm装置&降级npm不须要独自装置。在装置Node的时候,会连带一起装置npm。然而,Node附带的npm可能不是最新版本,最初用上面的命令,更新到最新版本。 $ sudo npm install npm@latest -g如果是 Window 零碎应用以下命令即可: npm install npm -g而后,运行上面的命令,查看各种信息。 # 查看 npm 命令列表$ npm help # 查看各个命令的简略用法$ npm -l # 查看 npm 的版本$ npm -v # 查看 npm 的配置$ npm config list -l解决下载包慢的问题因为npm的包服务器在国外,在国内速度很慢且不稳固,所以在国内就有很多企业架设了国内的镜像,不便国内开发者应用,日常过程中,咱们常常应用的是淘宝的镜像源,通过以下命令进行配置即可: // 1. 清空缓存 npm cache clean --force // 2. 切换新源 npm config set registry https://registry.npmmirror.com配置全局依赖的保留门路&缓存门路个别状况下,咱们都会对全局包保留门路和缓存门路进行自定义,自定义形式如下: 在想要保留的目录下新建【node_global】及【node_cache】文件夹,而后执行以下两条命令: npm config set prefix "/Users/Jelly/Repository/node_global"npm config set cache "/Users/Jelly/Repository/node_cache"npm罕用指令命令阐明npm init初始化一个新的npm我的项目,并生成package.json文件npm install装置我的项目依赖的所有包npm install <package>装置指定的包npm install --save <package>装置指定的包,并将其增加到dependencies字段中npm install --save-dev <package>装置指定的包,并将其增加到devDependencies字段中npm uninstall <package>卸载指定的包npm update更新我的项目依赖的所有包npm update <package>更新指定的包npm run <script>运行package.json文件中定义的脚本npm search <keyword>搜寻包npm ls列出我的项目依赖的所有包npm cache clear清空缓存罕用的命令就上表中的那么几个,根本笼罩了咱们日常90%的场景,如果遇到不在上表中的,再上网搜寻就OK了。 ...

February 21, 2024 · 1 min · jiezi

关于node.js:前端网络诊断技术方案

<article class=“article fmt article-content”><h2>背景</h2><p>用户在应用electron app的时候,常常会遇到白屏,服务器异样,网络异样等状况,然而用户却不晓得如何解决,所以须要提供一个能够给用户自行诊断网络的性能,一来不便用户本人疾速定位问题,自行解决,二来查看开发排查问题的工夫。</p><p>例如飞书在断开主动自行诊断网络状态,提醒用户设置网络。<br/></p><h2>性能需要</h2><p>性能需要能够参考飞书,飞书的网络诊断就是比拟残缺的交互例子<br/><br/>需要内容:</p><ol><li>反对网络状态诊断 - 检测网络是否在线或离线</li><li>反对nds解析诊断- 检测服务器域名是否能胜利解析dns</li><li>反对代理诊断 - 检测电脑是否开启了代理</li><li>服务稳定性剖析 - 检测服务器域名是否可连通</li></ol><table><thead><tr><th>性能</th><th>阐明</th><th>web</th><th>app</th></tr></thead><tbody><tr><td>反对网络状态诊断</td><td>检测网络是否在线或离线</td><td>☑️</td><td>☑️</td></tr><tr><td>反对nds解析诊断</td><td>检测服务器域名是否能胜利解析dns</td><td>✖️</td><td>☑️</td></tr><tr><td>反对代理诊断</td><td>检测电脑是否开启了代理</td><td>✖️</td><td>☑️</td></tr><tr><td>服务稳定性剖析</td><td>检测服务器域名是否可连通</td><td>☑️</td><td>☑️</td></tr></tbody></table><h2>技术选型</h2><h3>web技术诊断</h3><blockquote>有时候也有这样的需要,我想诊断web内所有域名服务器地址的可连通性。</blockquote><p>js引擎(浏览器)并没有提供ping相干的能力,并且也无奈通过xhr来做这种事件,因为这会波及到跨域,那么身下的计划就是通过资源申请,通过的做法就是发送一个img的申请,而最通用的就是申请服务器地址的favicon.ico。刚好就有这这样的一个插件能够帮忙做这样的事件:ping.js</p><p>装置ping.js</p><pre><code>$ npm install ping.js</code></pre><p>应用demo,data返回的是rtt值</p><pre><code class=“js”>var p = new Ping();// Using callbackp.ping(“https://github.com”, function(err, data) { // Also display error if err is returned. if (err) { console.log(“error loading resource”) data = data + " " + err; } document.getElementById(“ping-github”).innerHTML = data;});// You may use Promise if the browser supports ES6p.ping(“https://github.com”) .then(data => { console.log(“Successful ping: " + data); }) .catch(data => { console.error(“Ping failed: " + data); })</code></pre><p><strong>很显著这种形式对于很多场景都是不实用的,比方一个我的项目波及到其余域名的申请。</strong></p><h3>app技术诊断</h3><blockquote>app是原生利用,能够调用到计算机底层的api,就算不借助插件,都能够通过关上终端,ping域名,获取返回值,所以app做这件事件是非常容易的,这里咱们针对electron利用举例</blockquote><h2>诊断流程</h2><p></p><h3>获取域名信息</h3><p>网络信息的获取分为两种形式:</p><pre><code>1. 业务侧有输入框,用户手动输出 2. 获取我的项目配置的域名服务器地址 </code></pre><h3>网络状态</h3><p>网络问题产生时,网络状态往往是第一察看因素。如何去判断网络是否连贯上了网络:</p><ul><li>通用的判断形式:navigator.onLine,然而这个形式只会在机器未连贯到局域网或路由器时返回false,其余状况下均返回true。 也就是说如果用户路由器自身网络就不通的状况下是没有方法判断的。</li><li>进阶判断形式:收回一个申请,看申请返回的状态码或者拜访一个网络资源,比方图片。收回一个网络申请的网站起源,能够是一个固定稳固的动态域名服务器。</li></ul><h3>DNS解析</h3><p>依据域名,查问出对应 IP 信息。服务器域名,唯有正确的解析出 IP 后,能力胜利进行后续的网络连接流程,这里采纳node的nds模块即可。 <br/><code>Desktop: dns.lookup(node) </code></p><h3>ping连通性 与 traceRoute连通性</h3><p>对于如何诊断,以及ping和traceroute的原理,能够这篇博客:https://www.cnblogs.com/seanloveslife/p/11941736.html 。 <br/>这里咱们会用一个node的插件 node-net-ping 来实现这些操作,该插件不仅反对ping同时也反对traceroute,并且对这些操作的异样进行了很好的封装,简化调用过程。</p><p>如果在eletron应用过程中遇到问题:能够应用该插件node-ping,仅反对ping</p><h3>下载日志</h3><p>下载日志的思路就是把之前每一步诊断异样的日志通过electron-log或者其余日志插件写入到本地文件,再将本地的日志文件压缩,最初容许用户保留在指定的目录上面。<br/>这里重点看下压缩的过程:<br/><strong>压缩须要用到插件archiver</strong></p><pre><code class=“js”>const fs = require(‘fs’)const archiver = require(‘archiver’)/*** 压缩日志* @param {string} sourceFilePath* @param {string} outputFilePath* @returns*/const compressLogFolder = (sourceFilePath, outputFilePath) => { return new Promise((resolve, reject) => { try { const outputStream = fs.createwriteStream(outputFilePath); const archive = archiver(‘zip’, { zlib: { level: 9 }}) archive.pipe(outputStream) const data = fs. readFileSync (sourceFilePath, ‘utf8’); archive.append(data.toString(), { name: ’network.log’ }) archive.finalize(); outputStream.on( ‘close’, (res) = resolve(res)) ; outputStream.on( ’error’, (err) = reject(err)); } catch (error) { reject (error) } })}</code></pre></article> ...

February 12, 2024 · 1 min · jiezi

关于node.js:Nodejs-文件复制方法详解一步步教你如何实现

文件拷贝指的是将一个文件的数据复制到另一个文件中,使指标文件与源文件内容统一。Node.js 提供了文件系统模块 fs,通过该模块能够拜访文件系统,实现文件操作,包含拷贝文件。 Node.js 中文件拷贝办法在 Node.js 中,有几种罕用的办法能够用来实现文件拷贝: 1.应用 fs.copyFile() Node.js v8.5.0 版本引入了 fs.copyFile() 办法,能够更简略地拷贝文件: const fs = require('fs');fs.copyFile('source.txt', 'target.txt', (err) => { if (err) throw err; console.log('文件拷贝胜利!'); });fs.copyFile() 会依据操作系统的反对,尽可能应用零拷贝的形式复制文件,效率很高。 2.应用 fs.createReadStream() 和 fs.createWriteStream() 能够应用文件流将源文件流式传输到指标文件: const fs = require('fs');const readStream = fs.createReadStream('source.txt');const writeStream = fs.createWriteStream('target.txt');readStream.pipe(writeStream);writeStream.on('finish', () => { console.log('文件拷贝实现');});这种办法适宜解决大文件,能够分屡次将文件流传输。 3.同步办法 fs.readFileSync() 和 fs.writeFileSync() 应用 fs.readFileSync() 和 fs.writeFileSync() 能够实现同步文件拷贝: const fs = require('fs');let data = fs.readFileSync('source.txt');fs.writeFileSync('target.txt', data);但同步办法的性能并不如下面两种异步办法高。 基本概念在文件拷贝过程中,须要留神以下几个基本概念: 源文件门路和指标文件门路: 拷贝文件须要明确指定源文件的门路和指标文件的门路。同步和异步操作: Node.js 提供了同步和异步的文件操作方法。同步办法会阻塞代码执行,直到操作实现,而异步办法则不会阻塞代码,适宜于解决大量文件或网络操作。实际案例上面是一个应用 Express 框架的简略实际案例,演示如何在 Node.js 中拷贝文件: ...

September 28, 2023 · 2 min · jiezi

关于node.js:Node学习Kao框架

1.简介koa框架是一个遵循洋葱模型的轻量级的nodejs框架,将大部分工作都抛给中间件来解决,框架只专一于compose各个中间件,并依照use注册的程序一一执行中间件。 2.装置应用装置:npm install koa -s应用: const Koa = require('koa');const app = new Koa;app.listen(3000);3.中间件的应用const Koa = require('koa');const mount = require('koa-mount');const app = new Koa();app.use(mount('/api', function() { .....}));app.listen(80);以上代码应用了koa-mount来进行进行路由解决,应用koa实例上的use办法将mount函数返回的函数注册为中间件。以下是koa中use函数。 use(fn) { if (typeof fn !== 'function') throw new TypeError('middleware must be a function!'); if (isGeneratorFunction(fn)) { deprecate('Support for generators will be removed in v3. ' + 'See the documentation for examples of how to convert old middleware ' + 'https://github.com/koajs/koa/blob/master/docs/migration.md'); fn = convert(fn); } debug('use %s', fn._name || fn.name || '-'); this.middleware.push(fn); return this; }能够看到,一个函数中间件在use函数中先是判断是否为generator函数,如果是,应用koa-convert转换,最终都会放入koa实例的middleware数组中保留,供后续调用。 a.说一下isGeneratorFunction函数,这个函数的思路是通过Function动态创建一个generate函数,而后取其原型与传入的函数的原型比照,如果雷同阐明传入函数就是generate函数。 b.再说一下convert函数,这个函数在koa-convert包中,就是外部又引入了co库,将传入的generate函数包裹,达到自执行的成果。 ...

September 22, 2023 · 2 min · jiezi

关于node.js:Nodejs-20-几个令人大开眼界的特性

前言:欢送来到 Node.js 20 Node.js 20 曾经公布,带来了翻新和激动人心的新时代。这个开创性的版本于2023年4月18日首次亮相,并将在2023年10月公布长期反对(LTS)版本,并且将继续反对至2026年4月,上面小编就为大家介绍一下Node.js20的几个新个性: 1.Node.js 权限拜访 Node.js 20 正式推出了权限模型,这是 Rafael Gonzaga 提供的一项试验性功能,能够在程序运行时限度对特定资源的拜访。 要应用这个弱小的性能,只需启用 --experimental-permission 标记,例如: node --experimental-permissions myApp.js这将限度所有可用权限的拜访,这样就能够确保应用程序远离任何不受欢迎的入侵者。 文件读写零碎 要容许拜访文件系统,请应用--allow-fs-read和 --allow-fs-write标记: $ node --experimental-permission --allow-fs-read=* --allow-fs-write=* index.js Hello world! (node:19836) ExperimentalWarning: Permission is an experimental feature (Use `node --trace-warnings ...` to show where the warning was created)上面是具体指令的含意: --allow-fs-read=*- 它将容许所有FileSystemRead操作。--allow-fs-write=*- 它将容许所有FileSystemWrite操作。--allow-fs-write=/tmp/- 它将容许FileSystemWrite拜访该/tmp/ 文件夹。--allow-fs-read=/tmp/,/home/.gitignore- 它容许FileSystemRead拜访/tmp/文件夹和门路/home/.gitignore。2.自定义 ESM 加载器钩子 Node.js 20通过加载器提供的自定义钩子 (--experimental-loader=./mr.mjs)在专用线程上运行,确保所有都放弃颠三倒四。 以下是如何应用自定义加载器的疾速示例: loading.mjs export async function resolve(specifier, parentModuleURL, defaultResolve) { console.log("Resolving:", specifier); return defaultResolve(specifier, parentModuleURL); }export async function load(url, defaultLoad) { console.log("Loading:", url); return defaultLoad(url); }index.js ...

September 20, 2023 · 2 min · jiezi

关于node.js:效能工具之node在项目中的应用二以开发环境多后端服务切换问题为例

问题形容日常开发中,咱们前端在联调接口时,经常会遇到须要在多个后端ip服务切换的状况举个例子,一个前端要别离和三个后端 甲、乙、丙 联调其对应的本地接口前端须要先在vite.config.js(vue.config.js)文件中的proxy的target改成甲的ip服务地址甲的本地接口联调结束当前,须要把proxy的target再改成乙的,完了再改成丙的,如下图: 那咱们就想,能不能写一个脚本,在咱们启动我的项目执行"npm run dev"的时候,依据咱们的需要,主动帮忙咱们批改呢?相似于命令行的下拉框抉择的感觉那种(脚本批改代理转发,总比手动批改效率高一些)咱们先看一下最终的效果图gif图 解决问题效果图 上述gif就能清晰的看到最终想要成果(省去了手动批改的步骤了,略微了晋升了一点点开发效率) 那具体如何实现的呢?莫焦急,咱们先来温习(学习)一下几个常识常识温习1. inquirer命令行交互工具inquirer是一款十分优良的命令行交互工具很多的框架、我的项目、程序都用到了这个工具,比方vue-cli的脚手架如下截图: 说到这里,大家应该就明确了,inquirer工具,能够做很多交互成果,比方: '输入框''下拉框''确认框''明码框'等等...具体大家能够去官网粗疏学习一下:inquire官网 本例中,就是用到'下拉抉择框' 2. package.json文件中增加本人的脚本问题一:如何在package.json增加本人的脚本命令,并管制执行程序? 原来的脚本 "scripts": { "start": "npm run dev", "dev": "vite --host", "build": "vite build", "preview": "vite preview" },这个start脚本,相当于给npm run dev起一个别名,即执行npm start会调用npm run dev命令加上本人的脚本 "scripts": { "start": "npm run dev", "dev": "node ./startDevConf.js && vite --host", "build": "vite build", "preview": "vite preview" },咱们在原有的vite --host命令前,加上本人想要执行脚本文件的命令node ./startDevConf.js,并通过&&进行分隔示意先把后面的node ./startDevConf.js执行结束,再去执行后边的vite --host问题二:如何给本人写的脚本传递参数,并接管参数 比方咱们在package.json文件中,再加一个脚本,并附上参数helloWord "scripts": { "start": "npm run dev", "dev": "node ./startDevConf.js && vite --host", "build": "vite build", "preview": "vite preview", "params": "node ./paramsConf.js helloWord" },当咱们执行npm run params的时候,在对应的paramsConf.js文件中,有两种形式能够接管: ...

September 6, 2023 · 3 min · jiezi

关于node.js:Nodejs-使用-officecryptotool-读取加密的-Excel-和-Word文档

Node.js 应用 officecrypto-tool 读取加密的 Excel (xls, xlsx) 和 Word( docx)文档, 还反对 xlsx 和 docx 文件的加密(具体应用看文档)。临时不反对doc文件的解密 传送门:officecrypto-tool 读取加密的 Excel 示例 一:xlsx-populate // 只反对 xlsx, xlsx-populate 自带了解密性能,// 不过只反对 ecma376 agile 模式,也就是Office 生成的加密的docx,// WPS的就不行, WPS用的是 ecma376 standard 模式const XlsxPopulate = require('xlsx-populate');(async ()=>{ const input = await fs.readFile(`pass_test.xlsx`); const output = await officeCrypto.decrypt(input, {password: '123456'}); const workbook = await XlsxPopulate.fromDataAsync(output); // 或者可先判断文件是否是加密的 const isEncrypted = officeCrypto.isEncrypted(input); let output = input; if (isEncrypted) { output = await officeCrypto.decrypt(input, {password: '123456'}); } const workbook = await XlsxPopulate.fromDataAsync(output); })()二:@zurmokeeper/exceljs https://www.npmjs.com/package/@zurmokeeper/exceljs// 只反对 xlsx @zurmokeeper/exceljs 间接内置了解密性能,齐全兼容exceljs v4.3.0const Excel = require('@zurmokeeper/exceljs');(async ()=>{ // 从文件读取, 解密应用明码加密的excel文件 const workbook = new Excel.Workbook(); await workbook.xlsx.readFile(filename, {password:'123456'}); // 从流读取, 解密应用明码加密的excel文件 const workbook = new Excel.Workbook(); await workbook.xlsx.read(stream, {password:'123456'}); // 从 buffer 加载, 解密应用明码加密的excel文件 const workbook = new Excel.Workbook(); await workbook.xlsx.load(data, {password:'123456'});})()三:xlsx// xlsx 反对 xls 和 xlsxconst XLSX = require('xlsx');(async ()=>{ const input = await fs.readFile(`pass_test.xlsx`); // const input = await fs.readFile(`pass_test.xls`); // 或者xls const output = await officeCrypto.decrypt(input, {password: '123456'}); const workbook = XLSX.read(output); // 或者可先判断文件是否是加密的 const isEncrypted = officeCrypto.isEncrypted(input); let output = input; if (isEncrypted) { output = await officeCrypto.decrypt(input, {password: '123456'}); } const workbook = XLSX.read(output);})()四:node-xlsx// 其实 node-xlsx 只是对xlsx 进行了封装,外面还是调用 xlsx 去解析的const nodeXlsx = require('node-xlsx');(async ()=>{ const input = await fs.readFile(`pass_test.xlsx`); // const input = await fs.readFile(`pass_test.xls`); // 或者xls const output = await officeCrypto.decrypt(input, {password: '123456'}); const workbook = nodeXlsx.parse(output); // 或者可先判断文件是否是加密的 const isEncrypted = officeCrypto.isEncrypted(input); let output = input; if (isEncrypted) { output = await officeCrypto.decrypt(input, {password: '123456'}); } const workbook = nodeXlsx.parse(output);})()读取加密的 Word 示例 ...

September 5, 2023 · 2 min · jiezi

关于node.js:如何通过集群扩展-Nodejs-应用程序

如何通过集群扩大 Node.js 应用程序原文链接演示代码介绍当你在一个多核CPU的零碎上运行一个node程序,默认状况下会以单核的模式去创立一个过程。因为Node.js是以单线程的形式执行javascript代码,所以利用的所有申请都必须由单核上的线程去解决。如果应用程序有 CPU 密集型工作,操作系统必须安顿它们共享单个 CPU,直到实现。如果单个过程收到太多申请,可能会导致该过程不堪重负,从而导致性能降落。如果过程解体了,用户也不能持续拜访你的利用了。 Node.js引入了cluster模块去解决这个问题,它会在同一台计算机上创立同一个应用程序的多个正本并让它们同时运行。同时它也应用了round-robin 算法去实现负载平衡。如果一个实例解体了,剩下运行中的实例仍然能够为用户提供服务。得益于负载平衡,利用的性能也会显著进步。 在本教程汇总,你将会在一台领有四个或更多个 CPU 的机器上,应用 Node.js 的集群(cluster)模块来扩大一个应用程序。您将创立一个不应用集群的应用程序,而后将该利用改良到应用集群模块。你还将应用 pm2 模块来将应用程序扩大到多个 CPU。你将应用负载测试工具来比拟应用集群和不应用集群的应用程序的性能,以及评估 pm2 模块的体现。 筹备要追随学习本教程,你须要: 大于或等于4核零碎 a. 如果您应用的是 Ubuntu 22.04 近程服务器,您能够依照咱们的初始服务器设置来设置您的零碎. 在您的开发环境中设置 Node.js(最好大于16)。对express的根本理解步骤一:创立目录在这一步中,你将创立我的项目的目录并下载应用程序所需的依赖。在第二步中,你将应用 Express 构建应用程序。而后在第三步中,你将应用内置的 node-cluster 模块将其扩大到多个 CPU,在第四步中会应用 loadtest 软件包进行压力测试。接着你将应用 pm2 软件包扩大以后利用,并在第五步中再次进行压力测试。 首先,创立一个目录。您能够将其命名为 cluster_demo 或您喜爱的任何目录名称,而后进入目录,接着对其初始化 # 创立目录mkdir cluster_demo# 进入目录cd cluster_demo# 初始化npm init -y-y 选项通知 NPM 承受所有默认选项。 { "name": "cluster_demo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC"}这些属性须要与我的项目保持一致: ...

August 31, 2023 · 4 min · jiezi

关于node.js:Linux-部署-Nodejs-环境

Linux 部署 Node.js 环境Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,用来不便疾速地搭建易于扩大的网络应用。本文实用服务器零碎: CentOS 7Alibaba Cloud Linux 2Alibaba Cloud Linux 3操作步骤1.近程连贯 ECS 实例ssh 链接通过 Workbench 近程连贯通过客户端连贯2.装置利用2.1 装置 Nginxyum -y install nginxnginx -v2.2 装置 GITyum install git -y如要装置最新版本 git,请参考Centos7 装置最新版本 git 2.3 装置 Node.jsyum install nodejs -yyum install npm -y3.命令行丑化3.1 装置 zsh 和 oh-my-zsh装置 zsh yum install zsh切换默认 shell chsh -s /bin/zsh装置 oh-my-zsh git clone https://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zshcp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc3.2 语法高亮设置装置 git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting配置 ...

August 28, 2023 · 2 min · jiezi

关于node.js:效能工具之node在项目中的应用一

问题形容常言道,麻利开发...如何去麻利开发呢?路径有很多,其中有一种就是去发明一些“工具”,应用工具晋升开发效率比方,从最早的原生写法的HTML、CSS、JS,到起初的JQuery(工具)再到起初的ANGUALR、REACT、VUE框架(工具)包含一些UI组件库,WEBPACK、甚至是低代码平台都是一种工具实质上,就是让咱们少写代码,也能实现想要的成果明天笔者就给大家抛砖引玉一下,心愿诸位读者,读完当前,可能有所思考案例场景表格案例咱们晓得,开发中比拟常见的就是表格的展现,比方这样的: 咱们平时开发我的项目的时候,经常会把表格进行二次封装,通过JSON配置化的模式,配置一下,指定一些参数和字段,就可能间接渲染出咱们想要的成果了 代码大略是上面这样的 [ { "propName": "name", "labelName": "姓名", "width": 90, "fixed": false, "isSort": false }, { "propName": "age", "labelName": "年龄", "width": 90, "fixed": false, "isSort": false }, { "propName": "home", "labelName": "他乡", "width": 90, "fixed": false, "isSort": false }, { "propName": "remark", "labelName": "备注", "width": 90, "fixed": false, "isSort": false },]开发中,天然是复制粘贴啦,而后去批改其对应的键值对的值那么,咱们能不能自己搞一个工具,让咱们少一些复制粘贴呢?有的敌人问道,表格只有三五列,用得着,这么麻烦吗?笔者感叹,笔者曾遇到有100多列的表格的展现需要那总不能复制100屡次吧那怎么样少点复制操作,甚至可能主动生成呢?思路剖析咱们晓得,表格展现的字段啥的,来自后端建表的时候,定义的字段名称所以,源头在哪里呢?就在数据库的表的构造外面啊咱们关上数据库,设计表、查看表构造,是可能看到什么字段,以及相应的信息的,如下图 什么字段对应什么意思,失常来说,都会写在字段的正文外面的也就是说,一个字段,有一个字段的正文,绝对应的,也就是propName和labelName那这就好办了,咱们间接导出这个表的构造,就能够看到对应关系了,如下操作 导出的table.sql文件代码如下:/* Navicat Premium Data Transfer Source Server : lss Source Server Type : MySQL Source Server Version : 50562 Source Host : localhost:3306 Source Schema : xiyouji Target Server Type : MySQL Target Server Version : 50562 File Encoding : 65001 Date: 14/04/2021 08:56:05*/SET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS = 0;-- ------------------------------ Table structure for peopletable-- ----------------------------DROP TABLE IF EXISTS `peopletable`;CREATE TABLE `peopletable` ( `id` int(13) NOT NULL AUTO_INCREMENT COMMENT '惟一id', `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '姓名', `age` int(11) NULL DEFAULT NULL COMMENT '年龄', `home` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '他乡', `remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '备注', `is_delete_status` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '1失常、0删除', PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 31 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Compact;SET FOREIGN_KEY_CHECKS = 1;咱们看上述代码,就能明确,咱们想要的货色,从第24行开始到32行完结,中的CREATE TABLE创建表格的内容的,对应字段以及此字段的正文COMMENT的名字,完结的ENGINE = InnoDB AUTO_INCREMENT而,咱们又晓得,所谓的导出的.sql文件其内容不过就是一堆字符串罢了,毕竟咱们应用node的文件读取api可能拿到其对应字符串内容。如下fs.readFile('./table.sql', 'utf-8', (err, data) => { console.log('读取到的内容是字符串',data)})所以,当咱们拿到了字符串当前,就能够对字符串进行“加工”,比方找到对应关键字、进行提取、截取、拆散、加工组装成咱们所须要的JSON数组格局至于怎么加工的,笔者给大家提供了,一些代码,以供参考const fs = require('fs');let tableHeader = []// 判断是不是大写字母function isUpLetter(str) { var strCode = str.charCodeAt() return strCode >= 65 && strCode <= 90}// 动静往上走获取每行数据的第一个字,i变量,articalArr和end常量function getLineFirstWord(articalArr, i, end) { let lineWords = articalArr[end - i].trim() return lineWords[0]}// 找到字段范畴完结行(开始行好找,完结行标识为ENGINE即end往上找)function findPropEndLine(articalArr, end) { let i = 1 // 初始为1,就要往上找一行 while (isUpLetter(getLineFirstWord(articalArr, i, end))) { // 如果是大写的字母,就持续往上找 i = i + 1 // 直到不是大写字母,就阐明找到完结行地位了 } return end - i}// 蛇形转驼峰function hump(str) { if (!str.includes('_')) return str let s = "" for (let i = 0; i < str.length; i++) { if (str[i] == "_") { s = s + str[i + 1].toUpperCase() i = i + 1 } else { s = s + str[i] } } return s}// 截取propfunction getPropName(str) { let l = str.indexOf('`') let r = str.lastIndexOf('`') let resStr = str.slice(l + 1, r) return hump(resStr)}// 截取labelfunction getLabelName(str) { let l = str.indexOf('\'') let r = str.lastIndexOf('\'') return str.slice(l + 1, r)}// 导出JSON文件function exportJSON(tableHeader) { fs.writeFile('tableHeader.json', tableHeader, (err) => { if (err) { console.log(`失败了${err}`) } console.log('tableHeader导出胜利'); })}// 读取sql文件并加工成前端须要的格局fs.readFile('./table.sql', 'utf-8', (err, data) => { let articalArr = data.split('\n') // 应用换行符分隔成数组 let startLineIndex; // 开始行索引 let end; // end标识找到完结地位(完结地位再往上走几行才是prop、label完结地位) articalArr.forEach((item, index) => { if (item.includes('CREATE TABLE')) { startLineIndex = index } if (item.includes('ENGINE')) { end = index } }) startLineIndex = startLineIndex + 1 // 此行蕴含CREATE TABLE,再下一行才是真正prop、label数据 let endLineIndex = findPropEndLine(articalArr, end) // end标识不停往上走,直到不是大写字母 const propLabelArr = articalArr.slice(startLineIndex, endLineIndex + 1) // 截取真正应用范畴 /** * 遍历拿到prop和label,这才是真正的前端表头须要的数据值 * */ for (const item of propLabelArr) { let tableHeaderItem = { propName: getPropName(item), labelName: getLabelName(item), width: 90, // 定义默认值 fixed: false, // 定义默认值 } tableHeader.push(tableHeaderItem) } // 控制台输入复制粘贴应用 console.log(tableHeader); // 导出成json文件应用 exportJSON(JSON.stringify(tableHeader))});应用的话,如下图: ...

August 28, 2023 · 3 min · jiezi

关于node.js:moduleexports和exports应该用哪个

在 Node.js 编程中,模块是独立的性能单元,能够在我的项目间共享和重用。作为开发人员,模块让咱们的生存更轻松,因为咱们能够应用模块来加强应用程序的性能,而无需亲自编写。它们还容许咱们组织和解耦代码,从而使应用程序更易于了解、调试和保护。在这篇文章中,我将介绍如何在 Node.js 中应用模块,重点是如何导出和生产它们。 各种模块格局因为 JavaScript 最后没有模块的概念,因而随着工夫的推移,呈现了各种相互竞争的格局。上面列出了须要留神的次要格局: Asynchronous Module Definition (AMD)格局用于浏览器,应用define函数来定义模块。CommonJS (CJS)格局用于Node.js,应用require和module.exports来定义依赖和模块。npm 生态系统就是基于这种格局构建的。ES Module (ESM)格局。从 ES6(ES2015)开始,JavaScript 反对原生模块格局。它应用 export 关键字导出模块的公共 API,应用 import 关键字导入模块。System.register格局用于反对 ES5 中的 ES6 模块。Universal Module Definition (UMD)格局能够用于浏览器和Node.js。当一个模块须要被多个不同的模块加载器导入时,它就会十分有用。请留神,本文仅波及 Node.js 的规范 CommonJS格局。 引入模块Node.js带来了一系列内置模块,这样咱们就能够间接在代码中应用而不须要装置它们。要应用它们,咱们须要应用require关键字引入模块,并赋值给变量。而后就能够用它来调用模块公开的任何办法。 举个例子,要列举出目录下的内容,能够应用文件系统模块,以及该模块的readdir办法: const fs = require('fs');const folderPath = '/home/jim/Desktop/';fs.readdir(folderPath, (err, files) => { files.forEach(file => { console.log(file); });});请留神,在 CommonJS 中,模块是同步加载的,并依照模块呈现的程序进行解决。 创立并导出模块当初,让咱们看看如何创立本人的模块并导出它。创立user.js文件并增加下列代码: const getName = () => { return 'Jim';};exports.getName = getName;而后在同一文件夹下创立index.js,并增加下列代码: const user = require('./user');console.log(`User: ${user.getName()}`);应用node index.js运行代码,你会在终端上看到下列输入: ...

August 24, 2023 · 2 min · jiezi

关于node.js:NestJS系列从Nest-CLI开始入门

初识Nest JSNest 是一个渐进的 Node.js 框架,它能够在 TypeScript 和 JavaScript (ES6、ES7、ES8)之上构建高效、可伸缩的企业级服务器端应用程序。 Nest 基于 TypeScript 编写并且联合了 OOP(面向对象编程),FP(函数式编程)和 FRP (函数式响应编程)的相干理念。在设计上的很多灵感来自于 Angular,Angular 的很多模式又来自于 Java 中的 Spring 框架,依赖注入、面向切面编程等,所以咱们也能够认为:Nest 是 Node.js 版的 Spring 框架 Nest 框架底层 HTTP 平台默认是基于 Express 实现的,所以无需放心第三方库的缺失。 NestJs 的核心思想:就是提供了一个层与层间接的耦合度极小,抽象化极高的一个架构体系。 脚手架 NestJS CLI与其它框架一样,NestJS也有本人的脚手架,它可帮忙咱们疾速初始化Nest我的项目以及开发和保护 Nest 应用程序。 装置绝大多数人可能会抉择全局装置,因为不便,但须要留神的是,全局装置任何npm软件包都会将确保它们运行正确版本的责任留给咱们开发者本身。这还意味着,如果你有不同的我的项目,每个我的项目都将运行雷同版本的 CLI。 npm install -g @nestjs/cli⚠️这里须要留神Node版本,可能会遇到脚手架装置胜利了但初始化我的项目时报错,这里倡议应用高版本node,我这里用是node版本是16.19.0 当然你也能够不抉择全局装置,Nest提供了@nestjs/cli包同样能够应用nest命令 npx @nestjs/cli@latestnest命令装置完脚手架之后咱们能够通过nest --help看看它都有哪些命令: new|n该命令是用来初始化一个Nest我的项目的 nest new project-name该命令示意初始化一个名为project-name的Nest我的项目,并且会帮你装置好所有必要的依赖,几乎就是一步到位,十分棒\~ 上图中咱们能够看到nest|n,n代表nest的别名,所以为了不便,你也能够这样应用: nest n project-namegenerate|g该命令能够为咱们生成各种代码,其中包含:控制器Controller、服务service、模块module等。 # 生成控制器nest generate controller controller-name# 生成服务nest generate service service-name# 生成模块nest generate module module-name当你感觉一个一个生成很麻烦时,能够应用上面这个命令 ...

July 12, 2023 · 1 min · jiezi

关于node.js:记NVM-lsrermote等命令显示NA问题

记NVM ls-rermote等命令显示N/A问题前言针对前端开发,某次开发我的项目中用到的依赖是有node-sass(前端小伙伴都或多或少遇见node-sass装置不起的状况),尽管能够用sass代替,我的项目仍旧能够开发,然而本着以前开发共事也须要更改依赖,我只能忍痛冤屈本人解决(哎~~~他人是:死道友不死贫道,咱们却要反着来) 目前本地版本# 我目前依赖版本node: v16.16.0# 我的项目node-sass版本node-sass: ^4.14.1针对这个版本,我搜寻材料发现node版本须要下载v14的来自掘金的一个版本比照图网上已有版本针对网上已有版本的解决办法,我本人这边不实用,附上几个办法地址,根本大同小异,感觉根本来自stackoverflow大家能够参考参考: https://stackoverflow.com/questions/26476744/nvm-ls-remote-command-results-in-n-a/26477536#26477536 https://blog.csdn.net/qq_43897372/article/details/104526660 https://segmentfault.com/q/1010000007047646 我本人的实用计划因为我本人的nvm之前也是没问题的,是在遇见这个我的项目想要切换node版本才发现不能下载了,感觉只有 nvm --version 查看版本无效,其余都是失败的,办法也是在某次解决时,忽然发现 https://nodejs.org/dist 是超时,想到是不是我本人的源问题,设置成国内的镜像或者能够。事实也是证实这是对的 # 设置源的相干命令nvm node_mirror [url] 设置node镜像nvm npm_mirror [url] 设置npm 镜像# 执行nvm npm_mirror https://npmmirror.com/mirrors/npm/nvm node_mirror https://npmmirror.com/mirrors/node/# 我本人是间接给它配置在文件中,我应用的是MAC,所以在~/.zshrc增加环境变量export NVM_NODEJS_ORG_MIRROR=https://npmmirror.com/mirrors/node/export NVM_NPM_ORG_MIRROR=https://npmmirror.com/mirrors/npm/# 这个是淘宝的地址(地址应用看大家感觉)node: http://npm.taobao.org/mirrors/node/npm: http://npm.taobao.org/mirrors/npm/# 而后执行source ~/.zshrc更新环境变量# 关掉终端重启,执行下载命令即可总结针对我本人呈现的状况,倡议刚开始下载nvm的同学,能够间接就把源地址给更改掉,不然有时候呈现我这种状况很抓马(之前好好的,当初不行了)

July 10, 2023 · 1 min · jiezi

关于node.js:nodeJs快速入门

July 3, 2023 · 0 min · jiezi

关于node.js:如何搭建HTTP服务器调用DLL库

如何搭建HTTP服务器调用DLL库之前在帮敌人救急时,突然想到了这个办法,就是通过HTTP服务器调用DLL库。在某些状况下,咱们可能须要近程调用本地的 DLL 库。为了实现这个指标,咱们能够搭建一个 HTTP 服务器,通过发送 HTTP 申请来调用 DLL 库的函数。这种办法能够让咱们在不将 DLL 库放到近程机器上的状况下,实现对 DLL 函数的近程调用。 环境:MacOS + Node 18.0.0目标:酒店的房卡零碎,通过HTTP服务器调用DLL库,实现对房卡的读取、写入、删除等操作。 筹备阶段装置 Node.js:首先,咱们须要装置 Node.js。Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时,它能够帮忙咱们构建高效的网络应用程序。创立 HTTP 服务器:应用 Node.js 的内置模块,咱们能够轻松地创立一个简略的 HTTP 服务器。咱们将展现如何编写一个简略的 Node.js 脚本,以创立一个监听特定端口的 HTTP 服务器。这里咱们应用express框架。调用 DLL 库:为了调用 DLL 库,咱们将应用 Node.js 的 "ffi" 模块。该模块容许咱们加载和调用动态链接库(DLL)中的函数。咱们将演示如何应用 "ffi" 模块加载 DLL 库,并调用其中的函数。1. 搭建根底读取DLL库首先创立一个文件夹:mkdir http-dll,而后进入该文件夹:cd http-dll。 1.1 创立 package.json 文件在该文件夹下创立 package.json 文件:pnpm init -y。 1.2 装置依赖装置依赖:pnpm i ffi ref-struct ref-array ref。 1.3 读取搭建的过程不重要,为什么用的起因更重要,其次是思考怎么解决,最初是设计应用的办法。 如果这里咱们应用的是LockSDK.dll,这里只是为了演示,提供了根底的4个办法,因而以这4个办法为例子。 ...

June 25, 2023 · 2 min · jiezi

关于node.js:一个合格的-ChatGPT-应用需要具备什么一文带你打通-GPT-产品功能

我的项目地址:github.com/ltyzzzxxx/g… 欢送大家Star、提出PR,一起高兴地用 GPT Terminal 游玩吧~ 前言人不知;鬼不觉中,GPT Terminal 专栏曾经更新了 4 节内容啦~ 这 4 节内容曾经根本涵盖了一个 GPT 利用须要具备的基本功能。 然而,因为市面上类 GPT 利用切实是层出不穷,形形色色,这些利用耳濡目染地进步了大家的 "阈值",甚至让大家对此类利用有些审美疲劳,也有很多人认为此类利用只是简略地调用 Open AI 接口,没什么含金量。事实的确如此,但这仅只是从利用的角度来看,没有必要重复性地制作,进行无意义的 "内卷"。 假使咱们换个角度,从做一个优良的产品,又或是学习一些有用的技术角度登程,咱们或者又会有所播种。这也是明天写这篇文章的目标,我想尽可能凝练地提取出我在做 GPT Terminal 的过程中思考到的一些性能,其中波及到的不仅仅是调用 Open AI 接口,还有一些有意思的货色,仅供大家参考~ 合格的类 GPT 利用须要具备什么?在开始分享之前,我想先问大家一个问题,如果让你来做一款类 GPT 利用,你须要思考哪些方面,从而使得你的 GPT 不逊色于市面上其它产品? 如下是我通过思考与调研后,总结而成的思维导图。 根底性能反对 GPT 对话聊天性能 这一点是最根本的,这是任何一个类 GPT 利用都具备的特点反对 GPT 输入内容出现为 Markdown 格局 市面上绝大多数 GPT 利用均反对这一点,毕竟很多时候都是程序员在用 GPT,所以免不了和代码打交道。为了用户体验,在我看来这一性能是必须实现的。反对 GPT 输入模式为流式输入,即实现 “打字机” 成果 这一点在我看来也是必须的,因为从用户体验角度登程,流式输入可能让你感触到 GPT 仿佛是在一边思考,一边回复,更加仿真。同时,它也解决了响应工夫内,输入框白屏或加载的用户体验问题反对 GPT 记录上下文,即实现 “记忆” 性能 这在大多数场景下是必须的,除非每条对话都是独立的。咱们会通过询问 GPT 多个问题,而且这些问题之间互相关联,从而失去最终的答案。这其实也是 Prompt Engineering 中的一种技巧。 ...

June 24, 2023 · 1 min · jiezi

关于node.js:如何丝滑实现-ChatGPT-打字机流式回复ServerSent-Events

我的项目地址:github.com/ltyzzzxxx/g… 欢送大家Star、提出PR,一起高兴地用 GPT Terminal 游玩吧~ 前言明天来给大家整点 ChatGPT 的干货!想必大家用过 ChatGPT 都晓得,它是一个练习时长两年半,喜爱唱...(油饼食不食!) 它在响应咱们给它发送音讯的时候,并不是将一整个音讯间接返回给咱们,而是流式传输,如同打字机成果个别,逐步地将整个内容出现给咱们。(市面上的 GPT 个别都是如此) 这样的益处有两个,一方面是 GPT 一边响应一边返回后果,流式输入,响应效率大大晋升;另一方面是显著晋升了用户体验,给咱们的感觉就像是实在的对话一样,GPT 仿佛在思考问题的答案。 说到这里,不得不拜服 Open AI 这家公司。不仅仅实现了人工智能的冲破,掀起了第四次科技反动,而且它在做产品方面,也有很多值得咱们深刻学习与思考的中央。正如陆奇传授在前段时间一次演讲上说的个别: OpenAI 所代表的是全新的组织、全新的能力,他们所做的所有是要既能做科研、又能写代码、又能做产品,这些能力是分不开的。心愿能给大家在将来的学习与工作中带来一些新的思考维度~ 啊仿佛又跑题了,话不多说,咱们迅速进入正题! Server-Sent Events要想揭开 ChatGPT 实现流式传输的秘诀,那么肯定离不开这个技术 —— Server-Sent Events 它是一种服务端被动向客户端推送的技术,这一点是不是与 Websocket 有些相似,然而 SSE 并不反对客户端向服务端发送音讯,即 SSE 为单工通信。 通俗易懂一些了解就是,服务端与客户端建设了 长连贯,服务端源源不断地向客户端推送音讯。服务端就相当于河流的上游,客户端就相当于河流的上游,水往低处流,这就是 SSE 的流式传输。 大家简略理解一下即可,咱们还是须要在实战中深刻理解其具体如何应用。 GPT Terminal 调用流程 用户输出 GPT Terminal 中的 GPT 相干命令gpt chat -r ikun 请给我表演一下《只因你太美》!前端失去用户输出的命令并解析,将解析后果作为参数,申请后端。后端拿到参数后,渲染对应的角色模板(如:ikun),申请 GPT 服务。GPT 服务响应用户传入的音讯,并以 Stream 流模式返回给后端;后端也以 Stream 流模式返回给前端。咱们要害的点在于拆解 2/3/4 步,看看两次数据传输是如何用 Server-Sent Events 实现的! ...

June 22, 2023 · 2 min · jiezi

关于node.js:ElectronEgg-新一代桌面应用开发框架

为什么应用桌面软件(办公方向、 集体工具),依然是将来十几年 PC 端需要之一,进步工作效率electron 技术是风行趋势,百度翻译、阿里网盘、迅雷、有道云笔记 ......前端、服务端同学都能疾速入门 愿景所有开发者都能学会桌面软件研发 简略只需懂 JavaScript 开源gitee:https://gitee.com/dromara/electron-egg 3400+ github:https://github.com/dromara/electron-egg 900+ 3.4.0【减少】主过程mainserver反对加载动态资源,反对入口文件配置。【减少】config模块,减少isWebProtocol()/isFileProtocol()。【降级】降级electron到v21.4.4【降级】降级@electron/rebuild到v3.2.13【降级】demo分支,降级better-sqlite3到v8.4.0【修复】修复service多层调用。【优化】将打包配置独立出builder.json文件,精简package.json内容。应用场景1. 惯例桌面软件 - 性能 demowindows 平台macOS 平台linux 平台 - 国产 UOS、Deepinlinux 平台 (ubuntu) 2. vue、react、web 转换成桌面软件vue-ant-design(本地)禅道项目管理(web 我的项目地址) 3. 用户案例 更多案例拜访官网:electron-egg: 一个入门简略、跨平台、企业级桌面软件开发框架

June 14, 2023 · 1 min · jiezi

关于node.js:Nodejs-应用编译构建提速建议-京东云技术团队

编译构建的整体过程拉取编译镜像拉取缓存镜像拉取我的项目源码挂载缓存目录执行编译命令(用户自定义)长久化缓存上传编译镜像为什么在本地构建就快, 但编译机上很慢在编辑机上每次的构建环境都是全新的, 实现一次构建比本地须要多一些步骤: 现成的全局包缓存 VS 从新构建缓存: 咱能够先简略了解为咱应用 npm 的时候那个全局的缓存目录, 编辑机须要筹备长久化的缓存的环境, 包含下载、挂载以重建缓存, 如果缓存内容过大, 工夫也会绝对更长, 本地构建间接应用了稳固的本地文件系统;增量装置依赖 VS 全量装置依赖: 本地不太常常须要执行 install 的过程, 即便须要, 也因为有长久的 node\_modules 目录存在, 不须要全量装置, 但编辑机环境每次须要重新安装这个我的项目须要的所有依赖;增量构建 VS 全量构建: 本地构建默认会将构建缓存放到 node\_modules 目录下, 第二次构建的时候这些构建就能被用起来, 使得前面的构建更快, 但这个构建的默认缓存地位在编辑机上不会被长久化, 也就是每次须要全量构建.网络环境: 有些依赖包装置依赖内部网络甚至海内网络, 本地的网络环境比拟顺畅, 但编辑机的网络对与海内网的拜访没有保障.难以利用的劣势: 多核大内存, nodejs我的项目的构建, 大部分工作都在一个线程上执行了, 不好间接利用编译机的多核优势额定的步骤: 编译机须要下载镜像、制作并上传运行镜像、缓存内容长久化, 而本地个别只是产出包.所以从以上角度动手, 咱们能够基于这样的一些思路进行构建速度的优化: 优化镜像大小;善用长久化缓存实现增量构建(编辑机会对 /cache/ 目录下的内容进行长久缓存)充分利用多核优势: 比方 ts-loader 的类型校验就能够通过其它插件在独自的线程执行, eslint-loader 也反对多线程(但目前有bug, 不倡议应用). 再比方咱们能够对我的项目的各功能模块解耦, 拆成多个构建同时进行。 缩小不必要的构建: 比方合理配置 exclude 以精简构建文件范畴; 对于不常变动的文件, 拆出来一次构建, 下次复用. 判断是否可能有其它形式去掉对外网依赖的包如何剖析构建速度查看 /cache/ 目录大小:在编译命令中退出:du -sh /cache, 通过构建日志查看目录大小在整体编译命令前后都加上date, 能够看本人我的项目的构建过程耗时, 即编译命令执行工夫在次要的编译命令的每一行后面加上time, eg:time npm install能够看 install 过程的理论耗时, build 过程同理.比照整体构建工夫(网页上间接显示的工作工夫)与编译命令执行工夫(开端的 date 工夫 - 结尾的 date 工夫), 如果整体工夫超过编译命令执行工夫很多(> 1min30s), 可能是 /cache/ 目录或镜像过大导致的。以下为详情介绍: ...

May 26, 2023 · 3 min · jiezi

关于node.js:大白话讲解synchronized锁升级套路

synchronized锁是啥?锁其实就是一个对象,轻易哪一个都能够,Java中所有的对象都是锁,换句话说,Java中所有对象都能够成为锁。 这次咱们次要聊的是synchronized锁降级的套路synchronized会经验四个阶段:无锁状态、偏差锁、轻量级锁、重量级锁 顺次从消耗资源起码,性能最高,到消耗资源多,性能最差。锁原理先看看这些状态的锁为什么称之为锁,他们的互斥原理是啥。偏差锁当一个线程达到同步代码块,尝试获取锁对象的时候,会查看对象头中的MarkWord里的线程ID,如果这里没有ID则将本人的保留进去,拿到锁。若是有,则查看是否是以后线程,如果不是,就CAS尝试改,如果是,就曾经拿到了锁资源。这里具体说说CAS尝试批改的逻辑:它会查看持有偏差锁的线程状态。首先遍历以后JVM的所有存活的线程,如果能找到偏差的线程,则阐明偏差的线程还存活,此时会查看线程是否在执行同步代码块中的代码,如果是,则降级为轻量级锁,去持续进行CAS竞争锁。所以加了偏差锁之后,同时只有一个线程能够拿到锁执行同步代码块中的代码。轻量级锁查看对象头中的MarkWord里的Lock Record指针指向的是否是以后线程的虚拟机栈,如果是,拿锁执行业务,如果不是则进行CAS,尝试批改,若是批改几次都没有胜利,再降级到重量级锁。重量级锁查看对象头中的MarkWord里的指向的ObjectMonitor,查看owner是否是以后线程,如果不是,扔到ObjectMonitor里的EntryList中排队,并挂起线程,期待被唤醒。锁降级无锁个别状况下,新new进去的一个对象,临时就是无锁状态。因为偏差锁默认是有提早的,在启动JVM的前4s中,不存在偏差锁,然而如果敞开了偏差锁提早的设置,new进去的对象,就会增加一个匿名偏差锁。也就是说这个对象想找一个线程去减少偏差锁,然而没有找到,称之为匿名偏差。存储的线程ID为一堆0000,也没有任何地址信息。咱们能够通过以下配置敞开偏差锁提早。java复制代码//敞开偏差锁提早的指令-XX:BiasedLockingStartuoDelay=0 偏差锁当某一个线程来获取这个锁资源时,此时会胜利获取到,就会变为偏差锁,偏差锁存储线程的ID。当偏差锁降级时,会触发偏差锁撤销,偏差锁撤销须要等到一个平安点,比方GC的时候,偏差锁撤销的老本太高,所以默认开始时,会做偏差锁提早。若是间接有多个线程竞争,会跳过偏差锁,间接变为轻量级锁。 细说一下偏差锁撤销的过程,老本为啥高呢?当一个线程拿到偏差锁之后,会把锁的对象头的Mark Work中的线程id指向本人,当又有一个线程来了进行争抢导致锁降级的的时候,会暂停之前拿到偏差锁的线程,而后清空Mark Work中的线程id,减少一个轻量级锁,而后再复原暂停的线程继续执行。这也是为什么等到平安点再执行锁降级的起因,因为要暂停线程。 常见的平安点: 执行GC的时候办法返回之前调用某个办法之后抛出异样的地位一个循环的开端 轻量级锁当在呈现了多个线程的竞争,就会降级为轻量级锁,轻量级锁的成果就是基于CAS尝试获取锁资源,这里会用到自适应自旋锁,依据上次CAS胜利与否,消耗的工夫,决定这次自旋多少次。轻量级锁实用于竞争不是很强烈的场景,一个线程拿到锁,执行同步代码块,很快就解决完了。再来一个线程尝试一两次也拿到了锁,再去执行,不会让一个线程期待很久。重量级锁如果到了重量级锁,那就没啥说的了,如果有线程持有锁,其余想拿锁的就挂起,期待锁开释后被顺次唤醒。锁粗化&锁打消锁粗化/锁收缩锁收缩是编译Java文件的时候,JIT帮咱们做的优化,它会缩小锁的获取和开释次数。比方:java复制代码while(){ synchronized(){ // 屡次的获取和开释,老本太高,会被优化为上面这种}}synchronized(){ while(){ // 拿到锁后执行循环,只加锁和开释一次}} 锁打消:锁打消则是在一个加锁的同步代码块中,没有任何共享资源,也不存在锁竞争的状况,JIT编译时,就间接将锁的指令优化掉。比方java复制代码synchronized(){ int a = 1; a++; //操作局部变量的逻辑}

May 17, 2023 · 1 min · jiezi

关于node.js:NodeJs模块化之上半部分

模块化什么是模块化模块化是指解决一个简单问题时,自顶向下 逐层把零碎 拆解 成若干 模块 的过程。 对于整个零碎来说,模块是可组合、合成和更换的单元。 编程畛域中的模块化编程畛域中的模块化,就是恪守固定的规定,把一个大文件拆成独立并相互依赖的多个小模块。 把代码进行模块化拆分的益处: 进步了代码的复用性进步了代码的可维护性能够实现按需加载更多精彩内容,请微信搜寻“前端爱好者“, 戳我 查看 。 模块化标准模块化标准就是对代码进行模块化的拆分与组合时,须要恪守的那些规定。 例如: 应用什么样的语法格局来援用模块 在模块中应用什么样的语法格局向外裸露成员 模块化标准的益处:大家都恪守同样的模块化标准写代码,升高了沟通的老本,极大不便了各个模块之间的互相调用,利人利己。 模块化实例 -- nodejs模块 -- a.js function strParse(str) { console.log(str)}module.exports = strParse援用模块 index.js var strParse = require('./a') strParse('hello world!')Node.js 中的模块化 官网地址:https://nodejs.cn/api/ Node.js 中依据模块起源的不同,将模块分为了 3 大类,别离是: 全局模块:全局对象和全局变量外围模块:NodeJs自带的零碎模块自定义模块:用户创立的每个 .js 文件,都是自定义模块全局模块定义:随时随地都能够拜访,不须要援用还蕴含全局对象和全局变量。 外围模块定义:不须要独自下载,能够间接应用 require() 引入的模块。 常见的外围模块 path模块fs模块http模块自定义模块定义:本人封装的模块,能够间接应用 require() 引入。 Node.js 常见的外围模块官网地址:https://nodejs.cn/api/ path模块地址:https://nodejs.cn/api/path.html API演绎: 门路相干文件相干门路解析门路相干normalize:用于规范化给定的pathjoin:将所有给定的path片段连贯在一起resolve:解析为绝对路径isAbsolute:查看以后path是否为绝对路径path.normalize(path) 地址:https://nodejs.cn/api/path.html#pathnormalizepath path.normalize() 办法规范化给定的 path,解析 '..' 和 '.' 片段。 path <string>返回: <boolean>当找到多个间断的门路片段分隔符(例如 POSIX 上的 / 和 Windows 上的 \ 或 /)时,则它们将被平台特定门路片段分隔符(POSIX 上的 / 和 Windows 上的 \)的单个实例替换。 保留尾随的分隔符。 ...

May 16, 2023 · 3 min · jiezi

关于node.js:NodeJs基础之NRM与NPM

nrmnrm can help you easy and fast switch between different npm registries, now include: npm, cnpm, taobao, nj(nodejitsu). 译文:nrm能够帮忙您在不同的npm注册表之间轻松疾速地切换,当初包含:npm、cnpm、taobao、nj(nodejitsu)。 github地址:https://github.com/Pana/nrm 更多精彩内容,请微信搜寻“前端爱好者“, 戳我 查看 。 NRM 装置 NRM 常用命令 Nodejs 案例 -- 创立一个本地服务器var http = require('http'); var app = http.createServer((req, res) => { res.write('hello world!'); res.end()}) app.listen(3000,()=>{ console.log('服务器已启动')})NPMNPM 是JavaScript 的包管理工具,是 Nodejs 平台的默认包管理工具也是世界上最大的软件注册表,外面蕴含了 60 万个包构造。 NPM 的组成网站 https://www.npmjs.com/注册表( registry )命令行工具( CLI )NRM 常用命令npm -v:查看npm版本。npm init:初始化后会呈现一个package.json配置文件。能够在前面加上-y ,疾速跳过问答式界面。npm install:会依据我的项目中的package.json文件主动下载我的项目所需的全副依赖。npm install 包名 --save-dev(npm install 包名-D):装置的包只用于开发环境,不用于生产环境,会呈现在package.json文件中的devDependencies属性中。npm install 包名 --save(npm install 包名-S):装置的包须要公布到生产环境的,会呈现在package.json文件中的dependencies属性中。npm list:查看当前目录下已装置的node包。npm list -g:查看全局曾经装置过的node包。npm --help:查看npm帮忙命令。npm update 包名:更新指定包。npm uninstall 包名:卸载指定包。npm config list:查看配置信息。npm 指定命令 --help:查看指定命令的帮忙。npm info 指定包名:查看近程npm上指定包的所有版本信息。npm config set registry https://registry.npm.taobao.org: 批改包下载源,此例批改为了淘宝镜像。npm root:查看以后包的装置门路。npm root -g:查看全局的包的装置门路。npm ls 包名:查看本地装置的指定包及版本信息,没有显示empty。npm ls 包名 -g:查看全局装置的指定包及版本信息,没有显示empty。初始化 -- package.json ...

May 15, 2023 · 2 min · jiezi

关于node.js:Java8中的Stream的汇总和分组操作它并不难的

前言在后面的文章中其实大家也曾经看到我应用过collect(Collectors.toList()) 将数据最初汇总成一个 List 汇合。但其实还能够转换成Integer、Map、Set 汇合等。一、查找流中的最大值和最小值     static List<Student> students = new ArrayList<>();      static {         students.add(new Student("学生A", "大学A", 18, 98.0));         students.add(new Student("学生B", "大学A", 18, 91.0));         students.add(new Student("学生C", "大学A", 18, 90.0));         students.add(new Student("学生D", "大学B", 18, 76.0));         students.add(new Student("学生E", "大学B", 18, 91.0));         students.add(new Student("学生F", "大学B", 19, 65.0));         students.add(new Student("学生G", "大学C", 20, 80.0));         students.add(new Student("学生H", "大学C", 21, 78.0));         students.add(new Student("学生I", "大学C", 20, 67.0));         students.add(new Student("学生J", "大学D", 22, 87.0));    }      public static void main(String[] args) {         Optional<Student> collect1 = students.stream().collect(Collectors.maxBy((s1, s2) -> s1.getAge() - s2.getAge()));         Optional<Student> collect2 = students.stream().collect(Collectors.minBy((s1, s2) -> s1.getAge() - s2.getAge()));         Student max = collect1.get();         Student min = collect2.get();         System.out.println("max年龄的学生==>" + max);         System.out.println("min年龄的学生==>" + min);         /**          * max年龄的学生==>Student(name=学生J, school=大学D, age=22, score=87.0)          * min年龄的学生==>Student(name=学生A, school=大学A, age=18, score=98.0)          */    }复制代码Optional,它是一个容器,能够蕴含也能够不蕴含值。它是java8中人们常说的优雅的判空的操作。另一个常见的返回单个值的归约操作是对流中对象的一个数值字段求和。或者你可能想要求 平均数。这种操作被称为汇总操作。让咱们来看看如何应用收集器来表白汇总操作。二、汇总Collectors类专门为汇总提供了一些个工厂办法: ...

May 9, 2023 · 3 min · jiezi

关于node.js:一篇文章搞定什么是nodeJs它和NPM关系与应用

当初前端的入门门槛越来越高了,不再是单纯 html+css+js,各种前端框架 层出不穷,各种ui组件库层出不穷。 模块化,打包化,各种工具库层出不穷,前端变成大前端 ,甚至前端能够搞定整个我的项目,通过node作为服务端api, 这里咱们配角就是nodeJs 什么是nodejs javaScript是一门脚本语言,通常被用来编写、执行本地源代码。脚本语言须要一个解析器能力运行,HTML文件中的JavaScript代码由浏览器解析执行。而自行执行JavaScript代码则须要Node.js解析器能力运行。 每个解析器都是一个运行环境,容许JavaScript定义各种数据结构和执行各种计算,同时也容许JavaScript调用运行环境提供的内置对象和办法。浏览器环境下,JavaScript常被用来操作DOM等性能,因而浏览器提供了document等内置对象;在Node.js环境下,JavaScript通常用来解决磁盘文件和搭建HTTP服务器,因而Node.js提供了fs、http等内置对象。 Node.js是一个基于V8引擎的JavaScript运行环境。V8引擎具备疾速执行JavaScript代码的能力,并且性能十分优良。Node.js专一于优化一些非凡用例,并提供了代替的API,在非浏览器环境下更好地运行V8引擎。 作为一种服务器端JavaScript平台,Node.js可能疾速创立网络应用程序。同时,它也反对前后端JavaScript编程,为开发者提供了更高效的零碎设计和一致性。 NodeJS个性以下是一些使得Node.js成为软件架构师的首选的重要特色: 异步和事件驱动的Node.js库- 所有API都是异步非阻塞的,这意味着Node.js服务器不用期待API返回数据。它能够立刻挪动到下一个API调用,利用Node.js事件告诉机制来获取从API调用取得的响应。这种异步的事件驱动机制,使得服务器能够高效地响应并疾速解决大量申请。十分快的Node.js代码执行- Node.js代码在谷歌Chrome的V8 JavaScript引擎上运行,速度十分快。单线程但高度可扩大的Node.js - Node.js应用事件循环单线程模型,事件机制有助于服务器以非阻塞的形式响应申请,这使得服务器具备高度可扩展性。相比传统服务器应用创立线程等形式来解决申请,Node.js应用单线程和繁多程序处理形式,可能更好地解决大量申请,并具备更高的可扩展性。例如,Node.js能够比传统的Apache HTTP服务器解决更多申请。无缓冲的Node.js利用 - Node.js应用程序从来不须要缓冲任何数据。这些应用程序只需输入块中的数据,不须要在内存中缓冲大量数据。总之,以上特点都让Node.js成为软件架构师的首选,因为它能够高效地响应申请并解决大量申请,从而进步零碎的性能和可扩展性。 对立在Javascript浏览器之外的实现, CommonJS自从Netscape浏览器问世以来,JavaScript就始终在摸索本地编程的路。 可怜的是,过后服务端JavaScript的倒退基本上是借鉴其余服务器端语言的实现,因而不足特色和实用价值。 随着JavaScript在前端利用的广泛应用以及服务端JavaScript的推动,JavaScript现有的标准变得十分弱,难以满足JavaScript在大规模利用方面的需要。在以JavaScript为宿主语言的环境中,只有根本的原生对象和类型,其余对象和API取决于宿主的提供,因而,JavaScript不足以下性能: 模块零碎:没有原生反对的闭包作用域或依赖治理。规范库:除了一些外围库外,没有文件系统API和IO流API等。标准接口:不足像Web服务器或数据库这样的对立接口。包管理系统:不能主动加载和装置依赖。因而,CommonJS(http://www.commonjs.org)标准应运而生,目标是为了构建JavaScript在包含Web服务器、桌面、命令行工具以及浏览器中的生态系统。 CommonJS试图定义一套可供一般应用程序应用的API,以填补JavaScript规范库过于简略的有余。 其终极目标是制订相似于C ++规范库的标准,使基于CommonJS API的应用程序能够在不同的环境下运行,就像应用C ++编写的应用程序能够应用不同的编译器和运行时函数库一样。例如:模块、包、零碎、二进制、控制台、编码、文件系统、套接字、单元测试等等。 Node.js是CommonJS标准最风行的实现之一。Node.js实现了require办法作为其模块引入的办法,同时,NPM则基于CommonJS标准定义的模块标准,实现了依赖治理、模块主动装置等性能。 罕用框架express:欠缺、呈现早、文档全、社区大koa:超前,欠缺中hapi:简单,适宜大型项目NodeJS下载安装NodeJS提供了一些安装程序能够从nodejs.org下载安装。 治理Nodejs版本nn是一位鼎鼎大名的TJ Holowaychuk所写的Node.js模块,(鼎鼎大名的Express框架作者)旨在提供一个简略、直观的形式来治理Node.js版本。正如其名字所示,它谋求的理念就是简洁——无需应用子Shell、配置文件或臃肿的API,仅提供简略易用的性能。 n模块的次要性能是让用户能够轻松地装置、应用和治理不同版本的Node.js。如果您想要装置n模块,能够依照以下步骤进行操作: npm install n -g装置实现之后,间接输出n后输入以后曾经装置的node版本以及正在应用的版本(后面有一个o),你能够通过挪动高低方向键来抉择要应用的版本,最初按回车失效。 装置最新的版本 n latest装置稳固版本 n stablen前面也能够追随版本号比方: n v0.10.26n 0.10.26删除某个版本 $ n rm 0.10.1以指定的版本来执行脚本 $ n use 0.10.21 some.js常用命令 n # 显示所有已下载版本n 10.16.0 # 下载指定版本n lts # 查看近程所有 LTS Node.js 版本n run 10.16.0 # 运行指定的 Node.js 版本 n Display downloaded Node.js versions and install selection n latest Install the latest Node.js release (downloading if necessary) n lts Install the latest LTS Node.js release (downloading if necessary) n <version> Install Node.js <version> (downloading if necessary) n install <version> Install Node.js <version> (downloading if necessary) n run <version> [args ...] Execute downloaded Node.js <version> with [args ...] n which <version> Output path for downloaded node <version> n exec <vers> <cmd> [args...] Execute command with modified PATH, so downloaded node <version> and npm first n rm <version ...> Remove the given downloaded version(s) n prune Remove all downloaded versions except the installed version n --latest Output the latest Node.js version available n --lts Output the latest LTS Node.js version available n ls Output downloaded versions n ls-remote [version] Output matching versions available for download n uninstall Remove the installed Node.jsn 只实用于 macOS 和 Linux ,不适用于 Windows。 ...

May 8, 2023 · 4 min · jiezi

关于node.js:支持热插拔的ChannelHandler了解一下

前言在上一篇文章中:Netty:ChannelPipeline和ChannelHandler为什么会鬼混在一起? - 掘金 (juejin.cn)曾经提到了ChannelPipeline外面保护了ChannelHandler的链表,ChannelHandler次要就是负责外面的工夫进行拦挡和解决。 本篇次要介绍: ChannelHandler性能阐明接口的透传设计基于责任链模式的ChannelHandler实现的热插拔性能 ChannelHandler性能阐明 基于责任链模式实现,负责对IO事件进行拦挡和解决, 也能够终止事件的传递。 ChannelHandler反对注解,Netty提供了2个: Sharable:多个ChannelPipline专用同一个ChannelHandlerSkip:被Skip注解的办法不会被调用 ChannelHandlerAdapter 缩小臃肿的代码,只须要实现我感兴趣的事件就好,不感兴趣的不必实现 对于大多数ChannelHandler只会关怀很少一部分事件,其余事件就会疏忽交给下一个ChannelHandler解决。这就会有一个问题就是,用户本人定义的ChannelHandler必须实现ChannelHandler的所有接口,包含他不关怀的那些事件处理接口,这会让代码显得很臃肿。事件透传为了解决这个问题,Netty提供了ChannelHandlerAdapter,他的所有接口实现都是事件透传的。 透传:这个概念是通信传输的,指的是不论业务内容怎么变,只负责将内容从起源,传输到目的地 在这里,就是他实现了一个空的办法,留了个钩子Hook,外面没有解决任何事件,如果子类须要有相干须要的逻辑,重写就能够,没有也不须要实现。 然而前面Netty高版本之后,ChannelHandler也只有2个须要实现的办法: handlerAddedhandlerRemoved 不过它提供了这个Adaptor的思路也是十分不错的。ChannelHander热插拔性 ChannelPipeline反对运行态动静地增加或者删除ChannelHandler 首先解释一下什么是热插拔,对于玩键盘的人来说应该是再相熟不过了。 感激百度百科对本篇文章的鼎力资助。对于程序来说其实就是,反对在程序运行时动静地去批改。看到这里是不是想到很多相干的技术? ASM字节码反射AOP动静代理... 反对动静可插拔:意味着,咱们能够随时依据业务场景进行调整Handler的解决逻辑。 流量压力其实也是合乎28准则,20%的工夫可能接受的是一天80%的流量压力,80%的工夫其实只是承当一天流量的20%。 因而,咱们能够在业务高峰期的时候,动静地将零碎拥塞爱护、或者是一些限流的ChannelHandler增加到以后的ChannelPipeline中。 而后等流量压力小了之后,再把这些ChannelHandler给删掉 特地的,一些业务场景中Handler之间具备程序性比方HandlerB,须要在HandlerA后面执行ChannelPipleline反对在任意中央增加,他有: addFirtsaddBeforeaddLast 这些办法,在指定地位增加或者删除ChannelHandler线程安全性ChannelPipeline是线程平安的。N个业务线程能够并发操作CHannelPipeline而不存在多线程并发问题,这个是框架实现的。(他是通过简略的加锁synchronized乐观锁来实现的) 然而ChannelHandler不是线程平安的。这个还须要通过user-code,程序员来编写代码本人保障。总结ChannelHandler只在意本人关怀的事件,然而在父类外面定义了所有事件的解决办法,为了缩小代码的臃肿,子类不须要实现所有父类的形象办法,Netty把这些办法定义成事件透传。Netty的ChannelPipeline基于责任链的设计个性,他是一个链表的模式存在,所以对于ChannelHandler的增加和删除都十分不便,他具备热插拔性。

May 4, 2023 · 1 min · jiezi

关于node.js:xcrawl-v7-新版本已经发布

x-crawlx-crawl 是一个灵便的 Node.js 多功能爬虫库。灵便的应用形式和泛滥的性能能够帮忙您疾速、平安、稳固地爬取页面、接口以及文件。 如果你也喜爱 x-crawl ,能够给 x-crawl 存储库 点个 star 反对一下,感激大家的反对!GitHub: https://github.com/coder-hxl/x-crawl 重大扭转指纹降级: 进阶写法的 fingerprint 改名为 fingerprints ,为数组写法,外面寄存 DetailTargetFingerprintCommon 类型的对象,不便定制。外部会将外面的对象随机调配给指标。crawlPage 的指纹选项调整:进阶写法和具体指标写法的指纹配置的最大宽高改为可选项。代理降级:创立爬虫实例、进阶写法以及具体指标写法的 proxy 更改为对象写法, 领有 urls、switchByHttpStatus 以及 switchByErrorCount 这三个属性,urls 能够设置多个代理 URL ,外部默认先采纳第一个,switchByHttpStatus 设置遇到哪些不合乎的响应状态码须要切换代理,switchByErrorCount 设置像超时等谬误时达到多少次须要切换代理。该代理轮换性能须要配合谬误重试能力应用。返回值类型调整:CrawlCommonRes、CrawlPageSingleRes、CrawlDataSingleRes 以及 CrawlFileSingleRes 别离更名为 CrawlCommonResult、CrawlPageSingleResult、CrawlDataSingleResult 以及 CrawlFileSingleResult 特色能够通过在选项设置为 null 勾销下级对立设置的配置。DetailTargetFingerprintCommon 里的 userAgent 选项改写对象写法,并容许定制外面的主版本、次版本以及订正号的最大值和最小值。每个爬取指标都会获取一个新的 userAgent 。爬取后果新增 proxyDetails 属性,记录代理状态。指纹配置的 mobile 选项增加 'random' 属性值,容许由外部随机决定。终端提示信息进行简化以及色彩调整。 破绽修复在 linux 零碎上无奈创立多级不存在的文件夹。

April 27, 2023 · 1 min · jiezi

关于node.js:node如何在ES-modules中导入JSON文件

Node 14开始,开始反对ES module语法。JSON模块工作在Node.js版本>=17.1中,也能够应用--experimental-json-modules标记启用Experimental JSON模块 /* Experimental JSON import in Node.js $ node index.mjs*/// An import assertion in a static importimport info from `./package.json` assert { type: `json` };// An import assertion in a dynamic importconst { default: info } = await import("./package.json", { assert: { type: "json", },});我曾经习惯在node.js应用require导入json,例如const data = require('./some-file.json'),下面的写法无疑让人感到丧气。 如果你还不想应用这个实验性的性能,这篇文章解释了在ES模块中解决JSON的办法。 1. 手动读取和解析JSON文件其实就是应用fs模块读取文件,而后再用JSON.parse解析。 import { readFile } from 'fs/promises';const json = JSON.parse( await readFile( new URL('./some-file.json', import.meta.url) ));2. 利用CommonJS的require函数来加载JSON文件(举荐)import { createRequire } from "module";const require = createRequire(import.meta.url);const data = require("./data.json");createRequire容许你结构一个CommonJS require函数来应用CommonJS的典型性能,例如在Node.js的EcmaScript模块中读取JSON。 ...

April 26, 2023 · 1 min · jiezi

关于node.js:企业开发中Maven的基本使用

简述java开发中能够应用maven来治理依赖,引入依赖,构建最终jar文件,当然其中也可能须要解决依赖抵触问题。 治理依赖:通过<dependencyManagement>,申明依赖版本,进行依赖的版本控制的。引入依赖:通过<dependency>,进行依赖的理论引入。构建jar包:在须要打包的模块中增加<build>并退出定制插件plugin进行jar生成。依赖抵触:通过工具或者命令行排查抵触的依赖后,应用exclusion来排出抵触的依赖。 注: 依赖抵触能够应用idea的mavenhelper插件来查看,简略直观,也能够命令行应用mvn dependency:tree -Dverbose > tree.txt,在文件中检索conflict关键字。 maven应用前,须要设置好setting.xml配置文件,如镜像仓库。 maven的打包命令mvn clean package -Dmaven.test.skip=true指定配置文件打包mvn clean package -s setting.xml -Dmaven.test.skip=truemaven的仲裁机制:门路最近者优先,门路雷同第一声明者优先(门路间隔是从打包模块的pom开始算,第一申明是pom中申明的前后程序) maven罕用标签的应用的根本应用次要解说的内容:依赖罕用的两种援用形式,依赖的排除形式,依赖的作用域,<option>标签。 仓库引入 <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus.version}</version></dependency>复制代码 本地引入 注:须要在<build>中<plugin>中需增加<includeSystemScope>true</includeSystemScope> <dependency> <groupId>org.hibernate</groupId> <artifactId>kingbase8-hibernatedialect</artifactId> <version>5.2.17.Finaldialect</version> <scope>system</scope> <systemPath>${project.basedir}/../../../lib/hibernate-5.2.17.Finaldialect.jar</systemPath></dependency>复制代码 依赖排除 <dependency> <groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis-plus.version}</version><!--须要排除的依赖项--> <exclusions><!--排除的依赖无需申明版本号--> <exclusion> <groupId>com.github.jsqlparser</groupId> <artifactId>jsqlparser</artifactId> </exclusion></exclusions></dependency>复制代码 依赖的作用域标签<scope>,其默认值为compile。 <!-- Lombok --><dependency> <groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><scope>provided</scope></dependency>复制代码 拓展:<scope>import</scope> 只能在<dependencyManagement> 模块中应用,用于解决maven的单继承问题。 <option>标签,固定值为true <option>示意这个依赖是须要抉择是否引入的,如果须要引入则须要显示申明。举例:下方代码块是B模块的pom文件,A我的项目将B我的项目作为依赖后,这些带<option>的依赖并不会被引入,不会打进jar包,如果须要引入则显示的增加申明。<dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.10</version> <optional>true</optional><dependency><dependency> <groupId>postgresql</groupId> <artifactId>postgresql</artifactId> <version>8.4-701.jdbc3</version> <optional>true</optional><dependency></dependencies>复制代码 拓展常识:<classifier>标签,提供一个新的维度定义jar,个别为不同jdk版本生成jar文件 maven-resp (maven仓库)└── org └── apache └── maven ├── maven-artifacr-3.8.1-calss1.jar (jdk8生成一个jar) └── maven-artifacr-3.8.1-calss2.jar (jdk21生成一个jar)在pom文件中辨别环境的中增加<classifier>calss1</classifier>或<classifier>calss1</classifier>则不同环境生成不同jar文件样例:<properties> ...

April 25, 2023 · 2 min · jiezi

关于node.js:Java实现汉字转拼音多音字处理

背景:之前始终是前端间接调用公司公共城市组件获取城市列表,当初因为公共组件不再反对,须要由后端接口提供城市查问,并且依照城市首字母分组展现。后端实现:最开始抉择pinyin4j来实现,但发现对多音字的解决不太敌对,比方须要转重庆的拼音(能够看到后果并不是咱们想要的): 解决办法就须要本人定义多音字字典来实现,解析这个文件优先从这个文件中获取拼音,相似如下文件(字典格局可自行定义): 以上本人定义字典的形式比拟麻烦,通过在网上的一顿搜寻,发现能够应用具备语义的依赖包(底层也是用的自定义字典实现):<dependency> <groupId>com.hankcs</groupId><artifactId>hanlp</artifactId><version>portable-1.8.3</version></dependency>复制代码在我的项目中定义一个工具类:public class PinyinUtil { /** * 获取中文完整拼音 * * @param chineseStr * @return */public static String getPinyin(String chineseStr) { List<Pinyin> pinyins = PinyinDictionary.convertToPinyin(chineseStr); StringBuilder stringBuilder = new StringBuilder(); for (Pinyin pinyin : pinyins) { stringBuilder.append(pinyin.getPinyinWithoutTone()); } return stringBuilder.toString();}/** * 获取中文拼音首字母 * * @param chineseStr * @return */public static String getInitial(String chineseStr) { List<Pinyin> pinyins = PinyinDictionary.convertToPinyin(chineseStr); if (CollectionUtils.isEmpty(pinyins)) { return StringUtils.EMPTY; } return String.valueOf(pinyins.get(0).getPinyinWithoutTone().charAt(0));}}复制代码后果演示: ...

April 25, 2023 · 1 min · jiezi

关于node.js:SpringBoot定时任务Scheduled的多线程使用

一、@Scheduled注解简介@Scheduled是Spring框架中的一个注解,它能够用于配置定时工作,使得办法能够依照规定的工夫距离定时执行。在应用该注解时,咱们能够指定工作的执行工夫、循环周期、并发数等参数,从而实现定时工作的性能。在Spring Boot中,@Scheduled注解能够间接利用于办法上。二、@Scheduled的多线程机制在Spring Boot中,@Scheduled注解是基f于Java的ThreadPoolExecutor和ScheduledThreadPoolExecutor实现的。当咱们配置了一个定时工作后,Spring Boot会首先创立一个ScheduledThreadPoolExecutor线程池,并将定时工作增加到该线程池中期待执行。而后,在指定的工夫到来之后,线程池会为该定时任务分配一个线程来执行。如果该定时工作还未执行结束,在下一个周期达到时,线程池会为该工作再次调配一个线程来执行。通过这种形式,@Scheduled能够十分不便地实现周期性的定时工作f于Java的ThreadPoolExecutor和ScheduledThreadPoolExecutor实现的。当咱们配置了一个定时工作后,Spring Boot会首先创立一个ScheduledThreadPoolExecutor线程池,并将定时工作增加到该线程池中期待执行。而后,在指定的工夫到来之后,线程池会为该定时任务分配一个线程来执行。如果该定时工作还未执行结束,在下一个周期达到时,线程池会为该工作再次调配一个线程来执行。通过这种形式,@Scheduled能够十分不便地实现周期性的定时工作。三、@Scheduled的多线程问题尽管@Scheduled注解十分便捷,然而它也存在一些多线程的问题,次要体现在以下两个方面: 定时工作未执行结束时,后续工作可能会受到影响 在应用@Scheduled注解时,咱们很容易疏忽一个问题:如果定时工作在执行时,下一个周期的工作曾经到了,那么后续工作可能会受到影响。例如,咱们定义了一个间隔时间为5秒的定时工作A,在第1秒时开始执行,须要执行10秒钟。在第6秒时,定时工作A还没有完结,此时下一个周期的工作B曾经开始期待执行。如果此时线程池中没有足够的闲暇线程,那么定时工作B就会被阻塞,无奈执行。 多个定时工作并发执行可能导致资源竞争 在某些状况下,咱们可能须要编写多个定时工作,这些定时工作可能波及到共享资源,例如数据库连贯、缓存对象等。当多个定时工作同时执行时,就会存在资源竞争的问题,可能会导致数据谬误或者零碎解体。四、@Scheduled退出线程池来解决定时工作为了防止上述问题,能够将@Scheduled工作交给线程池进行解决。在Spring Boot中,能够通过以下两种形式来将@Scheduled工作退出线程池: 应用@EnableScheduling + @Configuration配置ThreadPoolTaskScheduler @Configuration@EnableSchedulingpublic class TaskSchedulerConfig { @Beanpublic TaskScheduler taskScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(10); scheduler.initialize(); return scheduler;}}复制代码在上述代码中,咱们通过配置ThreadPoolTaskScheduler来创立一个线程池,并应用@EnableScheduling注解将定时工作开启。其中,setPoolSize办法能够设置线程池的大小,默认为1。 应用ThreadPoolTaskExecutor @Configuration@EnableSchedulingpublic class TaskExecutorConfig { @Beanpublic ThreadPoolTaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(50); executor.setQueueCapacity(1000); executor.setKeepAliveSeconds(60); executor.setThreadNamePrefix("task-executor-"); return executor;}}复制代码在上述代码中,咱们通过配置ThreadPoolTaskExecutor来创立一个线程池,并应用@EnableScheduling注解将定时工作开启。其中setCorePoolSize、setMaxPoolSize、setQueueCapacity、setKeepAliveSeconds等办法能够用于配置线程池的大小和工作队列等参数。五、@Scheduled详细分析 在Spring Boot中,@Scheduled注解是基于Java的ThreadPoolExecutor和ScheduledThreadPoolExecutor实现的。当咱们配置了一个定时工作后,Spring Boot会首先创立一个ScheduledThreadPoolExecutor线程池,并将定时工作增加到该线程池中期待执行。而后,在指定的工夫到来之后,线程池会为该定时任务分配一个线程来执行。如果该定时工作还未执行结束,在下一个周期达到时,线程池会为该工作再次调配一个线程来执行。通过这种形式,@Scheduled能够十分不便地实现周期性的定时工作。 尽管@Scheduled注解十分便捷,然而它也存在一些多线程的问题,次要体现在以下两个方面: 定时工作未执行结束时,后续工作可能会受到影响在应用@Scheduled注解时,咱们很容易疏忽一个问题:如果定时工作在执行时,下一个周期的工作曾经到了,那么后续工作可能会受到影响。例如,咱们定义了一个间隔时间为5秒的定时工作A,在第1秒时开始执行,须要执行10秒钟。在第6秒时,定时工作A还没有完结,此时下一个周期的工作B曾经开始期待执行。如果此时线程池中没有足够的闲暇线程,那么定时工作B就会被阻塞,无奈执行。解决方案:针对上述问题,咱们能够采纳以下两种计划来解决:计划一:批改线程池大小为了防止因为线程池中线程数量有余引起的问题,咱们能够对线程池进行配置,进步线程池的大小,从而确保有足够的闲暇线程来解决定时工作。例如,咱们能够在application.properties或application.yml或者应用@EnableScheduling + @Configuration来配置线程池大小:spring.task.scheduling.pool.size=20复制代码多个定时工作并发执行可能导致资源竞争在某些状况下,咱们可能须要编写多个定时工作,这些定时工作可能波及到共享资源,例如数据库连贯、缓存对象等。当多个定时工作同时执行时,就会存在资源竞争的问题,可能会导致数据谬误或者零碎解体。解决方案:为了防止因为多个定时工作并发执行导致的资源竞争问题,咱们能够采纳以下两种计划来解决:计划一:应用锁机制锁机制是一种常见的解决多线程并发访问共享资源的形式。在Java中,咱们能够应用synchronized关键字或者Lock接口来实现锁机制。例如,上面是一个应用synchronized关键字实现锁机制的示例:private static Object lockObj = new Object();@Scheduled(fixedDelay = 1000)public void doSomething(){ synchronized(lockObj){ // 定时工作要执行的内容}}复制代码在上述代码中,咱们定义了一个动态对象lockObj,用来爱护共享资源。在定时工作执行时,咱们应用synchronized关键字对lockObj进行加锁,从而确保多个定时工作不能同时访问共享资源。计划二:应用分布式锁除了应用传统的锁机制外,还能够应用分布式锁来解决资源竞争问题。分布式锁是一种基于分布式系统的锁机制,它能够不依赖于单个JVM实例,从而可能保障多个定时工作之间的资源拜访不会抵触。在Java开发中,咱们能够应用ZooKeeper、Redis等分布式系统来实现分布式锁机制。例如,应用Redis实现分布式锁的示例代码如下:@Autowiredprivate RedisTemplate redisTemplate; ...

April 25, 2023 · 1 min · jiezi

关于node.js:Node工程的依赖包管理方式-京东云技术团队

作者:京东批发 陈震 在前端工程化中,JavaScript 依赖包治理是十分重要的一环。依赖包通常是我的项目所依赖的第三方库、工具和框架等资源,它们可能帮忙咱们缩小反复开发、提高效率并且确保我的项目能够正确的运行。 目前比拟常见的前端包管理器有 npm 和 Yarn,npm 是 Node.js 自带的包管理器,它能够装置、共享和散发 node.js 模块。最近pnpm也挺火的,通过并行下载和装置依赖项,在执行装置、更新、删除等操作时也更快。 但无论应用哪个包管理器,都要通过 package.json 文件的版本控制性能,保障在不同开发环境中的一致性。那么,package.json是如何进行依赖包治理的呢?咱们来一起深刻理解一下package.json的配置形式。 一、分类管理 依据package.json标准,依赖包被大抵分为以下几种:dependencies、devDependencies、optionalDependencies、peerDependencies和bundledDependencies总共5种。dependencies和devDependencies这两项是咱们应用较为频繁的。 1、dependencies工程在生产环境下也须要应用的依赖,例如react、antd等,应用npm装置插件时,会默认写入dependencies,也能够应用-P或--save-prod后缀。 2、devDependencies工程只有开发环境须要,生产环境不须要的依赖,例如eslint、babel等,应用-D或--save-dev来写入devDependencies。 3、optionalDependencies顾名思义,依赖是可选的,它们只有在运行时须要应用某些性能时才会被引入。通常用于实现某些可选的性能或优化。例如,一个包可能依赖于某个库来实现某种高级性能,然而这个库在某些环境下不存在或不可用。在这种状况下,能够将该库申明为可选依赖项,并在代码中查看该依赖项是否存在,而后依据状况来决定是否应用该高级性能。应用这个性能的工程比拟少,应用-O或--save-optional来写入optionalDependencies。 4、peerDependencies工程须要和这个依赖配套应用,个别用于解决插件依赖的外围库的版本和主我的项目依赖的外围库的版本不统一的问题,常见于开发配套插件。例如vuex@4.1.0申明了: "peerDependencies": { "vue": "^3.2.0"}表明vuex@4.1.0须要和vue@^ 3.2.0一起装置和应用,否则可能会出现异常。应用-O或--save-optional来写入optionalDependencies。 5、bundledDependencies工程依赖于某些特定的依赖项,并且心愿在运行时不用再次下载它们,则能够应用该选项。npm pack会将这些依赖一起放入生成的包中,并且在npm install时本工程,这些依赖项也会被一起装置。应用-B或--save-bundle来写入bundledDependencies。 看到这里你可能会有点疑难,为什么npm没有提供相似--save-peer的指令来写入peerDependencies呢?起因是peerDependencies暗示本工程将会被其余主模块应用,然而主模块自身并不需要在我的项目代码中显式应用。因而官网没有反对这一指令。 二、版本治理个别状况下,以上依赖配置(除了bundledDependencies)都须要指定依赖的版本号,版本号遵循semver语义化版本标准(Semantic Versioning)命名规定,能够用下图示意,如2.1.0、3.1.4-beta.2等。 当产生不兼容的 API 批改时,更新major位当做了向下兼容的功能性新增时,更新minor位当做了向下兼容的问题修改时,更新patch位可选的-tags即后行版本号,能够作为公布正式版之前的版本,格局是在订正版本号前面加上一个连接号(-),再加上一连串以点(.)宰割的标识符,标识符能够由英文、数字和连接号([0-9A-Za-z-])组成。 在 npm 的依赖的规定中,还有~、>、<、=、>=、<=、-、||、x、X、*等符号来形容实用的版本范畴; ^ :示意只锁定major,不小于指定版本号的版本范畴。例如^1.1.0,代表>=1.1.0 <2.0.0的版本范畴。~ :示意锁定major和minor,不小于指定版本号的版本号。例如~1.1.0,代表>=1.1.0 <1.2.0的版本范畴。x、X、*:示意通配符。例如1.1.x,也代表>=1.1.0 <1.2.0的版本范畴。默认状况下,若指定了一个版本范畴,npm会在范畴内装置最新版本的依赖。当应用 npm install XX 时,会装置以后最新版本,并在版本号前默认加上 ^ 符号。因而在装置运行老我的项目时,很容易呈现装置依赖后,我的项目启动报错的状况,起因就是某些依赖没有做到很好的向下兼容,导致重新安装的版本太高造成兼容性谬误,此时须要定位谬误依赖并回退版本。 三、npm install加载机制 npm install外围流程大抵分为以下5步: 1、npm 向 registry 查问依赖压缩包的网址。2、下载压缩包,寄存在cache目录,供下次装置时应用。3、解压压缩包到以后我的项目的node_modules目录。4、把所有装置的包信息写入package-lock.json,供下次装置时应用。5、持续解决依赖的依赖。install的过程速度也和每一个步骤非亲非故: (1)共享工程package-lock.json,能够防止向registry查问的步骤,并且保障不同环境下安装包的一致性。 (2)应用下载速度快的registry镜像(例如jd镜像)。 (3)事后进行依赖关系剖析构建依赖关系,而后最初再并行下载(例如yarn)。 心愿以上的介绍可能帮忙你更好的了解npm的依赖治理。

April 23, 2023 · 1 min · jiezi

关于node.js:如何在业务开发中使用适配器模式

适配器模式(Adapter Pattern):将一个类的接口变换成客户端所期待的另一种接口,从而使本来因接口不匹配而无奈在一起工作的两个类可能在一起工作。说人话:这个模式就是用来做适配的,它将不兼容的接口转换为可兼容的接口,让本来因为接口不兼容而不能一起工作的类能够一起工作。比方现实生活中的例子, 就像咱们提到的万能充、数据线、MAC笔记本的转换头、出国游览买个插座等等,他们都是为了适配各种不同的口 ,做的兼容。适配器模式定义 Target指标角色:该角色定义把其余类转换为何种接口, 也就是咱们的冀望接口, 例子中的IUserInfo接口就是指标角色。Adaptee源角色:你想把谁转换成指标角色, 这个“谁”就是源角色, 它是曾经存在的、 运行良好的类或对象, 通过适配器角色的包装, 它会成为一个簇新、 靓丽的角色。Adapter适配器角色:适配器模式的外围角色, 其余两个角色都是曾经存在的角色, 而适配器角色是须要新建设的, 它的职责非常简单: 把源角色转换为指标角色, 怎么转换? 通过继承或是类关联的形式。通用代码实现/** 指标角色 */public interface Target { void t1();void t2();void t3();}复制代码/** 指标角色实现类 */public class ConcreteTarget implements Target{ @Overridepublic void t1() { System.out.println("指标角色 t1 办法");}@Overridepublic void t2() { System.out.println("指标角色 t2 办法");}@Overridepublic void t3() { System.out.println("指标角色 t3 办法");}}复制代码/** 源角色:要把源角色转换成指标角色 */public class Adaptee { public void a1(){ System.out.println("源角色 a1 办法");}public void a2(){ System.out.println("源角色 a2 办法");}public void a3(){ System.out.println("源角色 a3 办法");}}复制代码基于继承的类适配器/** ...

April 18, 2023 · 2 min · jiezi

关于node.js:nodeprocess

processprocess模块容许你取得或者批改以后node过程的设置,不想其余的模块,process是一个全局过程(node主过程),你能够间接通过process变量间接拜访它。 process.argv<string[]>process.argv 属性返回数组,其中蕴含启动 Node.js 过程时传入的命令行参数。 第一个元素将是 process.execPath。 如果须要拜访 argv[0] 的原始值,请参阅 process.argv0。 第二个元素将是正在执行的 JavaScript 文件的门路。 其余元素将是任何其余命令行参数 process.chdir(directory)process.chdir() 办法更改 Node.js 过程的当前工作目录,如果失败则抛出异样(例如,如果指定的 directory 不存在)。 process.platformprocess.platform 属性返回用于标识编译 Node.js 二进制文件的操作系统平台的字符串。 aixdarwin // mac零碎freebsdlinuxopenbsdsunoswin32 // window零碎// 判断以后零碎是否为winprocess.platform === 'win32'process.arch: 返回CPU架构,值可能为: arm 、 arm64 、 ia32 、 mips 、 mipsel 、 ppc 、 ppc64 、 s390 、 s390x 和 x64 process.env:返回蕴含环境名称与值的键值对对象。比方process.env.NODE_ENV。process.cwd():返回以后的工作目录。process.platform:返回一个辨认操作系统的字符串:'aix','darwin' (macOS),'freebsd','linux','openbsd','sunos',或者'win32' (Windows)。process.uptime():返回Node.js过程已运行的秒数。process.cpuUsage():返回以后过程的用户和零碎CPU工夫的应用状况--例如{ user: 12345, system: 9876 }。将该对象传给该办法,以取得一个绝对的读数const process = require("process");const startUsage = process.cpuUsage();// { user: 31000, system: 46000 }process.memoryUsage():返回一个以字节为单位形容内存应用状况的对象。import { memoryUsage } from 'node:process';console.log(memoryUsage());// Prints:// {// rss: 4935680,// heapTotal: 1826816,// heapUsed: 650472,// external: 49879,// arrayBuffers: 9386// }heapTotal 和 heapUsed 执行 V8's 内存占用.external 指的是绑定到V8治理的JavaScript对象的c++对象的内存应用状况。rss,常驻内存设置大小,是过程在主内存设施中占用的空间量(这是调配的总内存的子集),包含所有c++和JavaScript对象和代码。arrayBuffers arrayBuffers指的是为arrayBuffers和SharedArrayBuffers调配的内存,包含所有Node.j的Buffers。它蕴含在external外面.process.version:返回Node.js版本的字符串。比方18.0.0。process.versions: 其中列出了Node.js及其依赖模块的版本字符串。import { versions } from 'node:process';console.log(versions);{ node: '11.13.0', v8: '7.0.276.38-node.18', uv: '1.27.0', zlib: '1.2.11', brotli: '1.0.7', ares: '1.15.0', modules: '67', nghttp2: '1.34.0', napi: '4', llhttp: '1.1.1', openssl: '1.1.1b', cldr: '34.0', icu: '63.1', tz: '2018e', unicode: '11.0' }process.pid: 显示过程的pidprocess.report:生成诊断报告。process.exit(code):退出以后应用程序。应用退出码0来示意胜利,或在必要时应用适当的错误代码。参考文章nodejs之process过程

April 16, 2023 · 1 min · jiezi

关于node.js:Threejs教程3D场景中插入新的几何体

举荐:将NSDT场景编辑器退出你3D工具链其余工具系列:NSDT简石数字孪生 3D场景中插入新的几何体后面课程绘制了一个立方体成果,上面通过three.js的球体构造函数SphereGeometry()在三维场景中增加一个球几何体。 SphereGeometry构造函数SphereGeometry(radius, widthSegments, heightSegments)第一个参数radius束缚的是球的大小,参数widthSegments、heightSegments束缚的是球面的精度,球体你能够了解为正多面体,就像圆一样是正多边形,当宰割的边足够多的时候,正多边形就会有限靠近于圆,球体同样的的情理, 有趣味能够钻研利用WebGL实现它的算法,对于three.js就是查找文档看应用阐明。 参数含意radius球体半径widthSegments管制球面精度,程度细分数heightSegments管制球面精度,程度细分数绘制球体网格模型应用THREE.SphereGeometry(60,40,40);替换立方体几何体代码new THREE.BoxGeometry(100, 100, 100);。 var box=new THREE.SphereGeometry(60,40,40);//创立一个球体几何对象更多几何体、threejs除了立方体、球体还提供了很多的常见几何体的API,这里不再过多解说,具体能够查看threejs文档,你能够在案例源码中测试上面的几何体代码。//长方体 参数:长,宽,高 var geometry = new THREE.BoxGeometry(100, 100, 100);// 球体 参数:半径60 经纬度细分数40,40var geometry = new THREE.SphereGeometry(60, 40, 40);// 圆柱 参数:圆柱面顶部、底部直径50,50 高度100 圆周分段数var geometry = new THREE.CylinderGeometry( 50, 50, 100, 25 );// 正八面体var geometry = new THREE.OctahedronGeometry(50);// 正十二面体var geometry = new THREE.DodecahedronGeometry(50);// 正二十面体var geometry = new THREE.IcosahedronGeometry(50);同时绘制多个几何体<embed width="770" height="500" src="1.插入多个几何体并偏移.html"/>这也比较简单,间接模拟立方体的代码就能够,须要创立一个几何体对象作和一个材质对象,而后把两个参数作为网格模型构造函数Mesh()的参数创立一个网格模型,而后再应用场景对象scene的办法.add()把网格模型mesh退出场景中。threejs的几何体默认位于场景世界坐标的原点(0,0,0),所以绘制多个几何体的时候,次要它们的地位设置。上面代码同时绘制了立方体、球体和圆柱三个几何体对应的网格模型。 // 立方体网格模型var geometry1 = new THREE.BoxGeometry(100, 100, 100);var material1 = new THREE.MeshLambertMaterial({ color: 0x0000ff}); //材质对象Materialvar mesh1 = new THREE.Mesh(geometry1, material1); //网格模型对象Meshscene.add(mesh1); //网格模型增加到场景中// 球体网格模型var geometry2 = new THREE.SphereGeometry(60, 40, 40);var material2 = new THREE.MeshLambertMaterial({ color: 0xff00ff});var mesh2 = new THREE.Mesh(geometry2, material2); //网格模型对象Meshmesh2.translateY(120); //球体网格模型沿Y轴正方向平移120scene.add(mesh2);// 圆柱网格模型var geometry3 = new THREE.CylinderGeometry(50, 50, 100, 25);var material3 = new THREE.MeshLambertMaterial({ color: 0xffff00});var mesh3 = new THREE.Mesh(geometry3, material3); //网格模型对象Mesh// mesh3.translateX(120); //球体网格模型沿Y轴正方向平移120mesh3.position.set(120,0,0);//设置mesh3模型对象的xyz坐标为120,0,0scene.add(mesh3); //辅助三维坐标系AxisHelper为了不便调试预览threejs提供了一个辅助三维坐标系AxisHelper,能够间接调用THREE.AxisHelper创立一个三维坐标系,而后通过.add()办法插入到场景中即可。// 辅助坐标系 参数250示意坐标系大小,能够依据场景大小去设置 ...

April 15, 2023 · 1 min · jiezi

关于node.js:node版本管理工具-nvm的安装

先保留一下咱们以后全局装置的工具装置nvm须要先卸载以后node,和以后全局装置的工具,如cli,eslint,ts...,所以咱们先保留一份,不便咱们前面装置nvm后再装置对应版本工具查看全局装置命令: npm ls -g --depth=0如: 卸载以后node如果是官网pkg安装包装置的sudo rm -rf /usr/local/{bin/{node,npm},lib/node_modules/npm,lib/node,share/man/*/node.*}如果是homebrew装置的 brew uninstall nodetip node卸载完,基于node的软件和命令行工具也须要重新安装,须要删除/usr/local/bin 上面的相干文件,其实他们都是软连贯,正主都在/usr/local/lib/node_modules/目录下.装置nvm装置形式详见:nvm官网文档装置报错问题解决 我在装置过程中可能会报错没有.nvm目录(具体报错信息不记得了 - -!),新建即可 cd ~mkdir .nvm再次运行装置命令会把安装文件填充到该目录,若提醒:command not found: nvm解决办法如下(3, 4,),若无报错跳过即可。复制以下的三行命令: export NVM_DIR="$HOME/.nvm"[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion到~/.bash_profile中 vim ~/.bash_profile #将复制的文本粘贴进来 粘到文本最初面即可tip 如果应用zsh,在.zshrc中也粘进去如图:如果以上设置仍不失效,尝试: vim ~/.bash_profilesource .bashrc应用nvmnvm ls ## 查找本电脑上所有的node版本nvm install ## 装置最新版本nvmnvm uninstall <version> ## 卸载制订的版本nvm use <version> ## 切换应用指定的版本nodenvm alias <name> <version> ## 给不同的版本号增加别名nvm unalias <name> ## 删除已定义的别名nvm current ## 显示以后版本nvm reinstall-packages <version> ## 在以后版本node环境下,从新全局装置指定版本号的npm包nvm on ## 关上nodejs管制nvm off ## 敞开nodejs管制nvm proxy ## 查看设置与代理好了,欢快的应用nvm来治理node吧 ...

April 13, 2023 · 1 min · jiezi

关于node.js:Nodejs工程师养成计划恐美人之迟暮

download:Node.js工程师养成打算全局视角零碎是指通过摄像头、传感器、雷达等安装收集数据,并利用数据处理技术生成全局视角信息的零碎。本文将介绍全局视角零碎的基本概念、利用场景以及将来发展趋势。 全局视角零碎的基本概念 数据采集全局视角零碎通过各种传感器、摄像头等安装收集数据。这些数据能够是图像、视频、声音、地位、速度等信息。 数据处理全局视角零碎通过算法解决采集的数据,例如计算机视觉、机器学习等技术。这些算法能够提取特色、辨认物体、跟踪静止等。 全局视角信息生成通过数据采集和解决,全局视角零碎能够生成全局视角信息。这些信息能够是实时的,也能够是记录下来的。 利用场景全局视角零碎能够利用于许多畛域,例如智能交通、智能家居、工业自动化等。 全局视角零碎的利用场景 智能交通全局视角零碎能够用于智能交通畛域,例如交通监控、交通流量管制、交通事故预测等。通过对交通数据的采集和解决,能够进步交通运行效率,缩小交通事故发生率。 智能家居全局视角零碎能够用于智能家居畛域,例如智能门锁、智能安防、智能照明等。通过对家庭环境的采集和解决,能够实现家庭自动化、智能化。 工业自动化全局视角零碎能够用于工业自动化畛域,例如机器人视觉、工厂安全监控、生产过程监控等。通过对工业数据的采集和解决,能够进步生产效率,缩小事变发生率。 全局视角零碎的将来发展趋势 智能化随着人工智能和机器学习等技术的倒退,全局视角零碎将更加智能化。例如,在智能交通畛域,全局视角零碎能够依据实时交通数据预测拥挤状况,提供更加精准的路线布局。 网络化全局视角零碎将逐步向网络化方向倒退。例如,在智能家居畛域,全局视角零碎能够与互联网相连,实现近程管制和数据共享。 安全性随着寰球平安威逼的一直减少

April 13, 2023 · 1 min · jiezi

关于node.js:nodeDNS

Node.js DNS 模块用于解析域名办法dns.lookup(hostname[, options], callback)将域名(比方 'runoob.com')解析为第一条找到的记录 A (IPV4)或 AAAA(IPV6)。参数 options能够是一个对象或整数。如果没有提供 options,IP v4 和 v6 地址都能够。如果 options 是整数,则必须是 4 或 6。 const dns = require('node:dns')dns.lookup('www.baidu.com', (err, address, family) => { console.log('address: %j family: IPv%s', address, family); // address: "14.119.104.189" family: IPv4});dns.lookupService(address, port, callback)应用 getnameinfo 解析传入的地址和端口为域名和服务。 dns.resolve(hostname[, rrtype], callback)将一个域名(如 'nodejs.org')解析为一个 rrtype 指定记录类型的数组. dns.reverse(ip, callback)反向解析 IP 地址,指向该 IP 地址的域名数组。 留神:不是每个IP地址都有反向DNS。有时这是成心的,最常见的是,因为多个域名映射到同一个IP地址。rrtyperecords containsResult typeShorthand method'A'IPv4 addresses (default)<string>dns.resolve4()'AAAA'IPv6 addresses<string>dns.resolve6()'ANY'any records<Object>dns.resolveAny()'CAA'CA authorization records<Object>dns.resolveCaa()'CNAME'canonical name records<string>dns.resolveCname()'MX'mail exchange records<Object>dns.resolveMx()'NAPTR'name authority pointer records<Object>dns.resolveNaptr()'NS'name server records<string>dns.resolveNs()'PTR'pointer records<string>dns.resolvePtr()'SOA'start of authority records<Object>dns.resolveSoa()'SRV'service records<Object>dns.resolveSrv()'TXT'text records[<string[]>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_...)dns.resolveTxt()dns.getServers()返回一个用于以后解析的 IP 地址数组的字符串。即返回以后主机默认网关ip地址列表 ...

April 13, 2023 · 1 min · jiezi

关于node.js:聊聊如何运用JAVA注解处理器APT

什么是APTAPT(Annotation Processing Tool)它是Java编译期注解处理器,它能够让开发人员在编译期对注解进行解决,通过APT能够获取到注解和被注解对象的相干信息,并依据这些信息在编译期按咱们的需要生成java代码模板或者配置文件(比方SPI文件或者spring.fatories)等。APT获取注解及生成代码都是在代码编译时候实现的,相比反射在运行时解决注解大大提高了程序性能APT的工作流程 什么是注解注:因为APT = 注解+ 注解处理器(AbstractProcessor)。因而须要理解什么是注解,不过对于java开发人员来说,注解应该是耳熟能详了,这边就不再阐述。如果不理解啥是注解的小伙伴,能够查看如下文章科普一下baike.baidu.com/item/%E6%B3…这边得特地说下元注解@Retention 因为APT是在java编译器应用,因而@Retention的value通常指定为source或者class,这样能够进步一点性能。就我集体而言,我偏向指定为sourceAPT之Element罕用元素以及Element元素罕用变量 1、罕用元素 这些元素映射到java,我通过一个例子大家应该就能够理解这些元素是指什么 2、Element元素罕用变量 更多element具体内容能够查看如下链接www.jianshu.com/p/899063e84…创立注解处理器步骤 创立注解类创立一个继承自 AbstractProcessor 的类,这就是 APT 的外围类注册处理器 创立注解处理器示例注: 示例要实现的性能,通过一个自定义注解AutoComponent,通过注解处理器扫描解析AutoComponent注解,并生成lybgeek.components,spring通过解析lybgeek.components,实现bean注册 1、创立注解类 @Documented@Retention(RetentionPolicy.SOURCE)@Target(ElementType.TYPE)public @interface AutoComponent { } 复制代码 2、创立一个继承自 AbstractProcessor 的类 这边需介绍这个类外面几个外围的办法 public synchronized void init(ProcessingEnvironment processingEnv)复制代码init办法能够让咱们处理器的初始化阶段,通过ProcessingEnvironment来获取一些帮忙咱们来解决注解的工具类// Element操作类,用来解决Element的工具Elements elementUtils = processingEnv.getElementUtils(); // 类信息工具类,用来解决TypeMirror的工具Types typeUtils = processingEnv.getTypeUtils(); // 日志工具类,因为在process()中不能抛出一个异样,那会使运行注解处理器的JVM解体。所以Messager提供给注解处理器一个报告谬误、正告以及提示信息的路径,用来写一些信息给应用此注解器的第三方开发者看Messager messager = processingEnv.getMessager(); // 文件工具类,罕用来读取或者写资源文件Filer filer = environment.getFiler(); 复制代码public Set<String> getSupportedAnnotationTypes()复制代码getSupportedAnnotationTypes办法用来指定须要解决的注解汇合,返回的汇合元素须要是注解全门路(包名+类名)public SourceVersion getSupportedSourceVersion()复制代码getSupportedSourceVersion办法用来指定以后正在应用的Java版本,个别返回SourceVersion.latestSupported()示意最新的java版本即可 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)复制代码process是注解处理器外围办法,注解的解决和生成代码或者配置资源都是在这个办法中实现。Java官网文档给出的注解处理过程的定义:注解处理过程是一个有序的循环过程。在每次循环中,一个处理器可能被要求去解决那些在上一次循环中产生的源文件和类文件中的注解。每次循环都会调用process办法,process办法提供了两个参数,第一个是咱们申请解决注解类型的汇合(也就是咱们通过重写getSupportedAnnotationTypes办法所指定的注解类型),第二个是无关以后和上一次循环的信息的环境。返回值示意这些注解是否由此 Processor 申明,如果返回 true,则这些注解已申明并且不要求后续 Processor 解决它们;如果返回 false,则这些注解未声明并且可能要求后续 Processor 解决它们。外围办法介绍完后,咱们通过示例来自定义一个注解处理器@AutoService(Processor.class)@SupportedOptions("debug")public class AutoComponentProcessor extends AbstractComponentProcessor { ...

April 12, 2023 · 1 min · jiezi

关于node.js:如何快速实现一个榜单排名的需求

首先,先建一个测试表create table praise_record(   id bigint primary key auto_increment,   name varchar(10),   praise_num int) ENGINE=InnoDB;复制代码而后让chatGpt给咱们生成几条测试数据INSERT INTO praise_record (name, praise_num) VALUES ('John', 5);INSERT INTO praise_record (name, praise_num) VALUES ('Jane', 3);INSERT INTO praise_record (name, praise_num) VALUES ('Bob', 10);INSERT INTO praise_record (name, praise_num) VALUES ('Alice', 3);INSERT INTO praise_record (name, praise_num) VALUES ('David', 7);INSERT INTO praise_record (name, praise_num) VALUES ('oct', 7);复制代码而后就能够开始实现咱们的需要:返回点赞的榜单,并返回排名rank() 应用rank()函数返回点赞的榜单, rank() over() 留神这里返回的rank字段要用反引号包起来select name, praise_num, rank() over (order by praise_num desc) as rank from praise_record;name  praise_numrankBob          10   1David         7   2oct           7   2John           5   4Jane           3   5Alice         3   5复制代码能够看到应用rank()函数的时候雷同的点赞数会返回雷同的排名,排名会产生跳跃,最终的排名不是间断的dense_rank() ...

April 12, 2023 · 2 min · jiezi

关于node.js:Netty服务开发及性能优化

Netty是一个异步基于事件驱动的高性能网络通信框架,能够看做是对NIO和BIO的封装,并提供了简略易用的API、Handler和工具类等,用以疾速开发高性能、高可靠性的网络服务端和客户端程序。 创立服务端服务端启动须要创立 ServerBootstrap 对象,并实现初始化线程模型,配置IO模型和增加业务解决逻辑(Handler)。在增加业务解决逻辑时,调用的是 childHandler() 办法增加了一个 ChannelInitializer,代码示例如下// 负责服务端的启动ServerBootstrap serverBootstrap = new ServerBootstrap();// 以下两个对象能够看做是两个线程组// boss线程组负责监听端口,承受新的连贯NioEventLoopGroup boss = new NioEventLoopGroup();// worker线程组负责读取数据NioEventLoopGroup worker = new NioEventLoopGroup(); // 配置线程组并指定NIO模型serverBootstrap.group(boss, worker).channel(NioServerSocketChannel.class) // 定义后续每个 新连贯 的读写业务逻辑 .childHandler(new ChannelInitializer<NioSocketChannel>() { @Override protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception { nioSocketChannel.pipeline() // 增加业务解决逻辑 .addLast(new SimpleChannelInboundHandler<String>() { @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception { System.out.println(msg); } }); } });// 绑定端口号serverBootstrap.bind(2002);复制代码通过调用 .channel(NioServerSocketChannel.class) 办法指定 Channel 类型为NIO类型,如果要指定为BIO类型,参数改成 OioServerSocketChannel.class 即可。其中 nioSocketChannel.pipeline() 用来获取 PipeLine 对象,调用办法 addLast() 增加必要的业务解决逻辑,这里采纳的是责任链模式,会将每个Handler作为一个节点进行解决。1.1 创立客户端客户端与服务端启动相似,不同的是,客户端须要创立 Bootstrap 对象来启动,并指定一个客户端线程组,雷同的是都须要实现初始化线程模型,配置IO模型和增加业务解决逻辑(Handler), 代码示例如下// 负责客户端的启动Bootstrap bootstrap = new Bootstrap();// 客户端的线程模型NioEventLoopGroup group = new NioEventLoopGroup(); ...

April 12, 2023 · 5 min · jiezi

关于node.js:简化你的代码提高生产力这10个Lambda表达式必须掌握

前言 Lambda表达式是一种在古代编程语言中越来越常见的个性,能够简化代码、进步生产力。这篇文章将介绍10个必须把握的Lambda表达式,这些表达式涵盖了在理论编程中常常用到的常见场景,例如列表操作、函数组合、条件筛选等。通过学习这些Lambda表达式,你将更加深刻地了解函数式编程的思维,可能更加高效地编写代码。 应用Lambda表达式进行汇合遍历未应用Lambda表达式:List<String> list = Arrays.asList("apple", "banana", "orange");for (String fruit : list) {System.out.println(fruit);}复制代码应用Lambda表达式:List<String> list = Arrays.asList("apple", "banana", "orange");list.forEach(fruit -> System.out.println(fruit));复制代码应用Lambda表达式进行排序未应用Lambda表达式:List<String> list = Arrays.asList("apple", "banana", "orange");Collections.sort(list, new Comparator<String>() {public int compare(String s1, String s2) { return s1.compareTo(s2);}});复制代码应用Lambda表达式:List<String> list = Arrays.asList("apple", "banana", "orange");Collections.sort(list, (s1, s2) -> s1.compareTo(s2));复制代码 应用Lambda表达式进行过滤未应用Lambda表达式:List<String> list = Arrays.asList("apple", "banana", "orange");List<String> filteredList = new ArrayList<String>();for (String fruit : list) {if (fruit.startsWith("a")) { filteredList.add(fruit);}}复制代码应用Lambda表达式:List<String> list = Arrays.asList("apple", "banana", "orange");List<String> filteredList = list.stream().filter(fruit -> fruit.startsWith("a")).collect(Collectors.toList());复制代码 ...

April 12, 2023 · 2 min · jiezi

关于node.js:nodecommandline

CLI Options--version or -vnode -v--eval or -e$ node -e 'console.log(3 + 2)'5--print or -p$ node -p '3 + 2'5-c, --check语法查看脚本而不执行。 node --check index.js-r, --require module它用于在启动时预加载指定的模块。它遵循require()的模块解析规定。Module能够是文件的门路,也能够是节点模块名。 --no-deprecation禁用弃用正告 --inspect[=host:port]应用node --inspect将在提供的主机和端口上激活查看器。如果没有提供,默认值是127.0.0.1:9229。附加到Node.js实例的调试工具应用Chrome调试协定通过tcp端口进行通信。 --inspect-brk[=host:port]--inspect-brk具备与--inspect选项雷同的性能,然而它会在用户脚本的第一行暂停执行。 --zero-fill-buffers--zero-fill-buffers会使new Buffer()主动填充0,然而这个new Buffer()写法官网已不举荐,你应该应用 Buffer.alloc代替。 --prof-process应用--prof-process, Node.js过程将输入v8分析器的输入 node --prof index.js环境变量NODE_DEBUG=module[,…]NODE_PATH=pathOPENSSL_CONF=file应用此环境变量,能够在启动时加载OpenSSL配置文件。 V8 Options你能够应用node --v8-options打印查看所有的命令行选项. 目前V8公开超出100个命令行选项--这里咱们只筛选几个它们所提供的一些性能,请审慎应用!--harmony应用harmony标记,您能够启用所有已实现的harmony个性。 如果你想在旧版本的nodejs中运行 ECMAScript 6 性能,你能够应用--harmony标记。最新版本的节点反对 ES6,因而不须要--harmony标记--expose-gcnode --expose-gc下面代码中,--expose-gc标记示意容许手动执行垃圾回收机制。 --max-old-space-size=SIZE (in megabytes)应用此选项,您能够设置堆上旧生代空间的最大大小,这将间接影响您的过程能够调配多少内存。 当您在低内存环境中运行时,此设置能够派上用场。 --optimize_for_size应用 --optimize_for_size 选项,V8引擎会优化内存空间的应用,这样很可能会升高利用的执行速度。 与后面的选项一样,它在低内存环境中也很有用。 --max-semi-space-size=SIZE (in megabytes)设置V8的革除垃圾收集器的semi-space的空间大小,单位为MiB(兆字节)。减少半空间的最大大小可能会以耗费更多内存为代价进步Node.js的吞吐量。 参考文章Mastering the Node.js CLI & Command Line Optionsnode --harmony 是做什么的?

April 10, 2023 · 1 min · jiezi

关于node.js:node节点是什么有哪些神操作

1.node节点(更具体的获取(设置)页面中所有的内容) 依据 W3C 的 HTML DOM 规范,HTML 文档中的所有内容都是节点: 元素是节点的别称,节点蕴含元素当然节点还有好多细化的品种; 有元素节点、属性节点、文本节点....... 节点的关系从这里真正的体现进去 根节点:root>>>>HTML没有父节点; 节点操作:(通过父子系关系) childNodes:获取以后元素的所有子节点; nodeType:节点品种,返回值是数字; nodeValue: 获取(文字)节点的文本内容; nodeName:返回node节点名称(#text,正文, 标签....); 一个能够找出元素节点的办法; 常见的节点类型: 1 元素(div、body、li、span ....... ) 2* 属性代表属性节点 (class,src,href) 3 文本节点(text节点) 8 代表正文节点 9 代表document节点; 2.innerHTML和nodeValue;(当innerHTML和nodeValue别离作为左值的时候) box.innerHTML = '< strong >abc< /strong >'; box.childNodes[0].nodeValue = '< strong >abc< /strong >'; innerHTML会将标签解析; nodeValue不会进行解析,会将标签名转译成字符串,间接输入; 3.attribute属性 document.getElementById('box').attributes // 获取所有,该节点的属性信息; document.getElementById('box').attributes.length;//返回属性节点个数 document.getElementById('box').attributes[0]; //返回第一个属性节点 document.getElementById('box').attributes[0].nodeType; //2,属性 document.getElementById('box').attributes[0].nodeValue; //属性值 document.getElementById('box').attributes['id']; //返回属性为 id 的节点 document.getElementById('box').attributes.getNamedItem('id'); // 获取 id 的节点; ...

April 6, 2023 · 1 min · jiezi

关于node.js:Spring-Security入门学习

意识Spring SecuritySpring Security 是为基于 Spring 的应用程序提供申明式平安爱护的安全性框架。Spring Security 提供了残缺的安全性解决方案,它可能在 Web 申请级别和办法调用级别解决身份认证和受权。因为基于 Spring 框架,所以 Spring Security 充分利用了依赖注入(dependency injection, DI)和面向切面的技术。外围性能对于一个权限治理框架而言,无论是 Shiro 还是 Spring Security,最最外围的性能,无非就是两方面: 认证受权 艰深点说,认证就是咱们常说的登录,受权就是权限甄别,看看申请是否具备相应的权限。认证(Authentication)Spring Security 反对多种不同的认证形式,这些认证形式有的是 Spring Security 本人提供的认证性能,有的是第三方规范组织制订的,次要有如下一些:一些比拟常见的认证形式: HTTP BASIC authentication headers:基于IETF RFC 规范。HTTP Digest authentication headers:基于IETF RFC 规范。HTTP X.509 client certificate exchange:基于IETF RFC 规范。LDAP:跨平台身份验证。Form-based authentication:基于表单的身份验证。Run-as authentication:用户用户长期以某一个身份登录。OpenID authentication:去中心化认证。 除了这些常见的认证形式之外,一些比拟冷门的认证形式,Spring Security 也提供了反对。 Jasig Central Authentication Service:单点登录。Automatic "remember-me" authentication:记住我登录(容许一些非敏感操作)。Anonymous authentication:匿名登录。...... 作为一个凋谢的平台,Spring Security 提供的认证机制不仅仅是下面这些。如果下面这些认证机制仍然无奈满足你的需要,咱们也能够本人定制认证逻辑。当咱们须要和一些“老破旧”的零碎进行集成时,自定义认证逻辑就显得十分重要了。受权(Authorization)无论采纳了下面哪种认证形式,都不影响在 Spring Security 中应用受权性能。Spring Security 反对基于 URL 的申请受权、反对办法拜访受权、反对 SpEL 访问控制、反对域对象平安(ACL),同时也反对动静权限配置、反对 RBAC 权限模型等,总之,咱们常见的权限治理需要,Spring Security 基本上都是反对的。我的项目实际创立 maven 工程我的项目依赖如下:<dependencies> <!-- 以下是>spring boot依赖--> <dependency> ...

April 4, 2023 · 4 min · jiezi

关于node.js:龙蜥-NodejsWebAssembly-SIG-重磅发布-NodejsNoslate-性能优化白皮书

文/严懿宸 前言JavaScript 是开发者数量最宏大的编程语言,Node.js以其跨平台、易用的个性宽泛应用于服务端、桌面利用等场景,但其通用性也限度了一些场景下特定的优化。咱们针对 Node.js 在服务端的场景,基于 SIG 成员在相干方向的摸索,提供了一系列性能优化、标准化测试计划。本次咱们首先公布的是 Noslate Anode 在 Intel 平台上的优化白皮书,最高能提供 50% 左右的性能晋升。 对于 SIG龙蜥社区 Node.js/WebAssembly SIG 专一于服务端的 Node.js 场景。SIG 的成员来自Intel、大淘宝技术部、阿里云编译器团队等企业的资深开发者,在 Node.js 不同场景有深度摸索和丰盛教训。Noslate Anode 是由淘宝开源的 Node.js 发行版,在兼容 Node.js 的前提下具备冷启动优化等额定个性,也是下一代龙蜥操作系统 Anolis OS 23 的默认 Node.js 发行版。欢送宽广 Node.js 开发者退出 SIG 参加探讨(入群形式见文末)。 白皮书内容本次公布的白皮书为《Node.js/Noslate 性能优化白皮书》,内容包含 Node.js 在理论业务中的应用场景,针对服务端负载的多种优化计划和性能测评。本次数据的测试平台专一于 Intel 平台。 Node.js 大大扩大了 JavaScript 语言的应用范畴。在 Noslate Anode 发行版的根底上,咱们将 Node.js/WebAssembly SIG 的服务端优化实际和理论应用场景精选为《Node.js/Noslate 性能优化白皮书》,全方位地介绍了服务端切实有效的优化伎俩及其实用场景,为 Node.js 语言社区作出贡献。 效果显著:白皮书优化能在理论场景、罕用框架下取得高达约 50% 的性能晋升。 实在场景:首次分享了 SIG 成员在实在业务中应用 Node.js 的理论利用。 多种优化:实用于不同场景的多种优化计划,提供了多层次的优化选项。 后续咱们也将持续公布 Node.js 和 Noslate 在龙蜥社区架构下的性能评估和优化报告,并打算开源标准化的 Node.js 服务端性能测试集。 ...

March 31, 2023 · 1 min · jiezi

关于node.js:面试官SpringBoot的启动流程清楚吗

SpringBoot 是一款轻量级的Java开发框架,它基于Spring框架,并对Spring框架进行了封装和简化,应用SpringBoot能够疾速构建出一些业务简略的应用程序,SpringBoot的启动流程是什么样的呢?接下来我来为大家简要介绍。SpringBoot的启动流程 加载配置文件与启动类当 SpringBoot 我的项目启动时,会首先读取我的项目中的配置文件,次要是 application.yml 和 application.properties 文件。这些配置文件会指定我的项目的启动端口号、数据库连贯等一些列配置信息。同时,SpringBoot也会加载启动类,这个启动类中有@SpringBootApplication注解,它标识着这个类是SpringBoot的启动类。初始化Spring容器加载完配置文件与启动类之后,SpringBoot会通过 Spring 框架来初始化 Spring 容器,包含依据配置文件中的配置信息注册bean,创立bean实例,实现依赖注入等操作。开启主动配置性能SpringBoot会主动扫描我的项目中的类,如果这些类中有@Configuration注解,SpringBoot将会读取这个类中被@Bean注解标记的办法去生成Bean实例并注入到Spring容器中。启动内嵌的Web服务器SpringBoot内置Tomcat和Jetty等Web服务器,当SpringBoot应用程序启动时,它会依据配置文件中的信息主动创立Tomcat或Jetty等Web容器,并将Spring容器注册到Web容器中,使得SpringBoot应用程序能够间接以Web应用程序的模式运行。启动SpringBoot应用程序最初一步是启动SpringBoot应用程序,它会依据之前的启动步骤创立好的 Spring 容器以及Web服务器,启动相应的线程进行服务解决。总的来说,SpringBoot的启动流程绝对简略,对于开发者而言,只须要关注本人的业务逻辑和所须要的依赖库,就可能疾速构建出一款可运行的应用程序。面试答复当面试官询问无关SpringBoot的启动流程时,应该对以下几点进行答复:首先,SpringBoot会读取配置文件与启动类,配置文件指定了我的项目的各种配置信息,启动类是应用程序的入口。而后,SpringBoot会应用Spring框架初始化Spring容器,蕴含创立bean实例、依赖注入等操作。接着,SpringBoot会开启主动配置性能,扫描我的项目中的类,主动注册bean,以便于能够不便地应用。在实现了主动配置后,SpringBoot会启动内嵌的Web服务器,比方Tomcat或Jetty,在Web服务器上部署应用程序。最初,SpringBoot会启动应用程序自身,启动相应的线程进行服务解决。 在答复时须要强调SpringBoot是Spring框架的封装,并对开发者进行了很多简化,导致SpringBoot启动流程相较于Spring框架的启动流程更为简略,而且SpringBoot内置Web服务器的个性更是让SpringBoot的应用变得像应用个别的Java应用程序一样简略,非常适宜疾速构建Web应用程序。

March 28, 2023 · 1 min · jiezi

关于node.js:Nodejs学习本地句柄等概念理解

1. 在C++层间解释下Local和persistentLocal 和 persistent 都是在 C++ 层面上用于治理异步 I/O 操作的句柄。其中,Local 句柄是一种长期的句柄,用于解决一次性的 I/O 操作,比方读取一个文件或者发送一个网络申请。Local 句柄在 I/O 操作实现后会主动敞开,因而不须要手动开释资源。persistent 句柄则是一种长期存在的句柄,用于解决须要继续监听的 I/O 操作,比方监听一个网络端口或者一个文件的变动。persistent 句柄须要手动开释资源,否则会导致内存透露。在 Node.js 中,Local 和 persistent 句柄都是通过 node::ObjectWrap 类来实现的。具体来说,能够通过继承 node::ObjectWrap 类来创立一个自定义的 Local 或 persistent 句柄类,而后在类的构造函数中调用 Wrap() 办法来将 C++ 对象绑定到 JavaScript 对象上。在 JavaScript 层面上,能够通过 new 关键字来创立一个 Local 或 persistent 句柄对象,而后调用对象的办法来进行异步 I/O 操作。2.解释Local主动开释内资源Local 句柄是一种长期的句柄,用于解决一次性的 I/O 操作,比方读取一个文件或者发送一个网络申请。Local 句柄在 I/O 操作实现后会主动敞开,因而不须要手动开释资源。这是因为 Local 句柄是通过 node::MakeCallback() 办法来实现异步 I/O 操作的,该办法会在 I/O 操作实现后主动调用回调函数,并且会主动开释 Local 句柄。因而,你不须要手动开释 Local 句柄,也不须要放心内存透露的问题。3.解释下v8::HandleScope和v8::Contextv8::HandleScope 是 V8 引擎中的一个类,用于治理 JavaScript 对象的生命周期。在 V8 引擎中,所有的 JavaScript 对象都是通过 v8::Handle 类来示意的,而 v8::HandleScope 则是用于治理这些 v8::Handle 对象的生命周期的。具体来说,v8::HandleScope 能够将一组 v8::Handle 对象绑定到一个作用域中,当作用域完结时,v8::HandleScope 会主动开释这些 v8::Handle 对象,从而防止内存透露的问题。v8::Context 是 V8 引擎中的一个类,用于示意 JavaScript 的执行上下文。在 V8 引擎中,每个 JavaScript 对象都是在某个执行上下文中创立的,而 v8::Context 则是用于治理这些执行上下文的。具体来说,v8::Context 能够将一组 JavaScript 对象绑定到一个执行上下文中,从而实现 JavaScript 对象的隔离和沙箱。在 Node.js 中,每个 JavaScript 模块都会被包装成一个 v8::Context 对象,从而实现模块之间的隔离和沙箱。4.这个v8::Handle是Localv8::Handle 有两种类型:Local 和 Persistent。其中,Local 句柄是一种长期的句柄,用于解决一次性的 I/O 操作,比方读取一个文件或者发送一个网络申请。Local 句柄在 I/O 操作实现后会主动敞开,因而不须要手动开释资源。这是因为 Local 句柄是通过 node::MakeCallback() 办法来实现异步 I/O 操作的,该办法会在 I/O 操作实现后主动调用回调函数,并且会主动开释 Local 句柄。因而,你不须要手动开释 Local 句柄,也不须要放心内存透露的问题。而 Persistent 句柄则是一种长期存在的句柄,用于解决须要继续监听的 I/O 操作,比方监听一个网络端口或者一个文件的变动。Persistent 句柄须要手动开释资源,否则会导致内存透露。在 Node.js 中,Local 和 Persistent 句柄都是通过 node::ObjectWrap 类来实现的。具体来说,能够通过继承 node::ObjectWrap 类来创立一个自定义的 Local 或 Persistent 句柄类,而后在类的构造函数中调用 Wrap() 办法来将 C++ 对象绑定到 JavaScript 对象上。在 JavaScript 层面上,能够通过 new 关键字来创立一个 Local 或 Persistent 句柄对象,而后调用对象的办法来进行异步 I/O 操作。5.是在应用Local时必须先创立一个HandleScope吗,不然Local的资源无奈主动开释?是的,如果你在应用 Local 句柄时没有创立 HandleScope,则会导致 Local 句柄无奈主动开释,从而导致内存透露的问题。因而,在应用 Local 句柄时,你须要先创立一个 HandleScope 对象,而后将 Local 句柄绑定到该对象中,从而实现 Local 句柄的主动开释。具体来说,你能够依照以下步骤来应用 Local 句柄:创立一个 HandleScope 对象。创立一个 Local 句柄对象,并将其绑定到 HandleScope 对象中。在 HandleScope 对象的作用域内应用 Local 句柄对象。当 HandleScope 对象的作用域完结时,Local 句柄对象会主动开释。以下是一个应用 Local 句柄的示例代码:void MyFunction() { v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::HandleScope handle_scope(isolate); v8::Local<v8::String> str = v8::String::NewFromUtf8(isolate, "Hello, world!"); printf("%s\n", *v8::String::Utf8Value(str));}在下面的代码中,咱们首先创立了一个 HandleScope 对象,而后创立了一个 Local 句柄对象 str,并将其绑定到 HandleScope 对象中。在 HandleScope 对象的作用域内,咱们应用了 str 对象,并将其转换成了一个 C 字符串,而后将其打印进去。当 HandleScope 对象的作用域完结时,str 对象会主动开释,从而防止了内存透露的问题。 ...

March 27, 2023 · 4 min · jiezi

关于node.js:nvm安装

nvm装置版本地址:https://github.com/coreybutler/nvm-windows/tree/1.1.10[ ps:在运行nvm install 的时候,有可能会呈现无权限装置的问题,请 以管理员身份 运行 cmd ]nvm -v //查看nvm版本 nvm --version :显示 nvm 版本nvm list //显示版本列表 nvm list :显示已装置的版本(同 nvm list installed nvm list installed:显示已装置的版本 nvm list available:显示所有能够下载的版本nvm install //装置指定版本node.js nvm install 14.5.0:装置 14.5.0 版本的 node.js nvm install latest:装置最新版本nvm use //应用指定版本node nvm use 14.5.0: 切换到 14.5.0 版本的 node.js --lts // 主动切换到长期反对版本 --lts=<LTS name> // 主动切换到指定名称的node长期反对版本 nvm uninstall <version> //卸载指定版本 node nvm uninstall 14.5.0:卸载到 14.5.0 版本的 node.js nvm uninstall --lts // 卸载长期反对版本的node nvm uninstall --lts=<LTS name> // 卸载一个指定名称的长期反对版本的node ...

March 26, 2023 · 1 min · jiezi

关于node.js:挂屏笔记-复习-nodejs-接口跨域配置连接数据库身份认证

cors实现跨域配置装置 cors 后可通过引人中间件的形式引入到代码中 npm install cors const cors=require("cors")要在调用路由之前 app.use('URL前缀',cors())自定义响应头实现跨域配置CORS 响应头 Access-Control-Allow-Origin 容许拜访的地址 res.setHeader('Access-Control-Allow-Origin','容许跨域拜访的 URL,能够写通配符*')CORS 响应头 Access-Control-Allow-Methods 默认仅反对 GET,PODST,HEAD 申请 res.setHeader('Access-Control-Allow-Methods','*')nodejs连结,操作数据库装置,引入mysql的包 npm install MySQLconst mysql = require('mysql')建设连结 const db = mysql.createPool({ host:"127.0.0.1", user:"root", password:"admin123", databases:"mydatabases"})执行sql let SQL_str='select * from user'db.query('SQL_str',(err,results)=>{ if(err) return console.log(err.message) 查问操作执行胜利后后果集存储到 results 中 console.log(results)}) 执行有参数的 sql db.query('SQL str',['SQL_str中须要的参数','字符串中用?占位'],(err,results)=>{ if(err) return console.log(err.message) // 如果是增删改操作,则 results.affectedRows 为受影响的行数 console.log(results)}) 如果数据对象的每个属性和数据表的字段一一对应,能够应用便捷写法 // 插入let user1={name:'zhangsan',age:18}const sqlStr1='Insert into user_table SET ?'db.query(sqlStr1,user1,(err,results)=>{ console.log(results)})// 更新let user2={name:'zhangsan',age:18}const sqlStr2='UPDATE user_table SET ? where id=?'db.query(sqlStr2,[user2,user2.id],(err,results)=>{ console.log(results)})

March 25, 2023 · 1 min · jiezi

关于node.js:Nodejs搭建Https服务

Node.js用于做小程序后盾服务,域名要求必须是Https协定。在Node.js开启Http服务是非常简单的,如下: const http = require('http');const server = http.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'text/html;charset=utf8' }); res.end('拜访胜利')});server.listen(8080, () => { console.log('服务已开启');})如果想应用Https服务须要两步:1. 须要有一份SSL证书;2. 应用Node.js本身的Https模块。 SSL证书获取SSL证书形式有两种: 本人借助openSSL工具生成SSL证书下载某些平台提供的收费/付费的SSL证书(举荐)我是应用某云平台提供收费的证书 点击下载后抉择服务器类型 下载后的文件别离是以.key、.pem为后缀,其中.key文件是base64加密私钥,.pem文件是base64加密的证书 应用Node.js本身的Https模块开启一个服务相较Http,它多了一个options参数。 const https = require('https');const fs = require('fs');const path = require('path');const options = { key: fs.readFileSync(path.join(__dirname, './ssl/9499016_www.linglan01.cn.key')), cert: fs.readFileSync(path.join(__dirname, './ssl/9499016_www.linglan01.cn.pem')),};const server = https.createServer(options, (req, res) => { res.writeHead(200, { 'Content-Type': 'text/html;charset=utf8' }); res.end('拜访胜利')});server.listen(8080, () => { console.log('服务已开启');})因为SSL证书我绑定的域名是www.linglan01.cn ,当我应用https://127.0.0.1:8080 拜访服务时与绑定的域名不相符,它会被拦挡拜访,仅容许 www.linglan01.cn 拜访。 ...

March 24, 2023 · 1 min · jiezi

关于node.js:复习nodejs-挂屏笔记

模块化模块分类:内置模块,自定义模块(须要补全门路),第三方模块require('加载模块时会执行被加载的代码')nodejs 模块化具备模块作用域,不能间接拜访被引入模块内的变量自定义模块中有module对象,可通过module.exports 能够向外共享成员 自定义模块中有exports对象,默认和module.exports指向同一对象,require() 失去的永远是 module.exports commonjs标准:每个模块外部,module变量代表以后模块module变量是一个对象,它的expor属性(即module.exports)是对外的接口。require 一个模块,其实是加载该模块的 module.expoorts属性。 三个内置模块file 模块载入模块 let fs=require('fs')用来读取指定文件中的内容 fs.readFile('./test.text1','utf8',(err,satastr)=>{console.log(satastr)})用来向指定的文件中写入内容 fs.wirteFile('./file.txt','要写入的str','能够省略,默认utf8',(err)=>{})path 模块载入模块 let path=requeire('path')文件所在的门路 console.log(__dirname)门路拼接 path.join('url片段1','URL片段2...')残缺的文件名 path.basename(fpath)去掉扩展名的文件名 path.basename(fpath,'.html')文件的扩展名 path.extname(fpath)http 模块载入模块 let http=require('http')创立实例 let server=http.createServer()为服务器实例绑定request事件,监听客户端的申请 server.on('request',function(req,res){ // 客户端申请的url地址 console.log(req.url) // 客户端申请的类型 console.log(req.method) // 设置响应头:示例为解决返回中文编码问题 res.setHeader('Content-Type','text/html:charset=utf-8') // 向客户端返回一些内容并完结本次申请 res.end('欢送拜访')})启动服务器 server.listen(80,()=>{console.log('服务器启动了:http://127.0.0.1')})nodemon主动重启服务,开发期间批改了代码不须要手动重启 npm install -gnodemon应用nodemon filename.js命令代替node File.js命令来启动服务 express基于nodejs,疾速,凋谢,极简的web开发框架(基于http模块) npm i express@4.17.1创立并启动一个服务导入express const express = require('express')创立服务器实例 const app = express()监听get申请 app.get('/user/:id',(req,res)=>{})监听post申请 app.post('/user',(req,res)=>{})调用 app.listen(端口号,启动胜利后的回调函数)启动服务 app.listen(80,()=>{})req申请体与res响应体获取url前面用问号拼接的参数,默认是个空对象 console.log(req.query)获取url前面的动静参数(冒号占位),如:127.0.0.1//user/22145 console.log(req.params)常见申请体内容格局,可间接通过已有中间件后获取json 格局要通过中间件app.use(express.json()) url-encoded 格局要通过中间件app.use(ecpress.urlexcoded({extended:false})) ...

March 20, 2023 · 1 min · jiezi

关于node.js:手把手教你验证码检验的登录

在网站理论利用过程中,为了避免网站登录接口被机器人轻易地应用,产生一些没有意义的用户数据,所以,采纳验证码进行肯定水平上的拦挡,当然,咱们采纳的还是一个数字与字母联合的图片验证码模式,后续会讲到更加简单的数字计算类型的图片验证码,请继续关注我的博客。实现思路博主环境:springboot3 、java17、thymeleaf 拜访登录页面 登录 验证验证码验证账号、明码验证胜利时,生成登录凭证,发放给客户端验证失败时,跳转回登录信息,并保留原有填入信息 退出 将登录凭证批改为生效状态跳转至首页 拜访登录页面的办法曾经在前文阐明过了,就不多加赘述了,展现一下代码:// 登录页面@RequestMapping(path = "/login", method = RequestMethod.GET)public String getLoginPage() { return "/site/login";}复制代码拜访完登录页面,咱们就要进行信息输出,然而,当初,还没有把验证码信息正确展示进去,所以,接下来,咱们先来实现验证码的局部。所需两个数据表 SQL 代码如下:注:注册流程可看前文.一文教你学会实现以邮件激活的注册账户代码 - 掘金 (juejin.cn)-- user表DROP TABLE IF EXISTS user; SET character_set_client = utf8mb4 ;CREATE TABLE user ( id int(11) NOT NULL AUTO_INCREMENT, username varchar(50) DEFAULT NULL, password varchar(50) DEFAULT NULL, salt varchar(50) DEFAULT NULL, email varchar(100) DEFAULT NULL, type int(11) DEFAULT NULL COMMENT '0-普通用户; 1-超级管理员; 2-版主;', status int(11) DEFAULT NULL COMMENT '0-未激活; 1-已激活;', activation_code varchar(100) DEFAULT NULL, header_url varchar(200) DEFAULT NULL, create_time timestamp NULL DEFAULT NULL, PRIMARY KEY (id), KEY index_username (username(20)), KEY index_email (email(20))) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8; ...

March 20, 2023 · 3 min · jiezi

关于node.js:ThreadLocal源码分析

在网站理论利用过程中,为了避免网站登录接口被机器人轻易地应用,产生一些没有意义的用户数据,所以,采纳验证码进行肯定水平上的拦挡,当然,咱们采纳的还是一个数字与字母联合的图片验证码模式,后续会讲到更加简单的数字计算类型的图片验证码,请继续关注我的博客。实现思路博主环境:springboot3 、java17、thymeleaf 拜访登录页面 登录 验证验证码验证账号、明码验证胜利时,生成登录凭证,发放给客户端验证失败时,跳转回登录信息,并保留原有填入信息 退出 将登录凭证批改为生效状态跳转至首页 拜访登录页面的办法曾经在前文阐明过了,就不多加赘述了,展现一下代码:// 登录页面@RequestMapping(path = "/login", method = RequestMethod.GET)public String getLoginPage() { return "/site/login";}复制代码拜访完登录页面,咱们就要进行信息输出,然而,当初,还没有把验证码信息正确展示进去,所以,接下来,咱们先来实现验证码的局部。所需两个数据表 SQL 代码如下:注:注册流程可看前文.一文教你学会实现以邮件激活的注册账户代码 - 掘金 (juejin.cn)-- user表DROP TABLE IF EXISTS user; SET character_set_client = utf8mb4 ;CREATE TABLE user ( id int(11) NOT NULL AUTO_INCREMENT, username varchar(50) DEFAULT NULL, password varchar(50) DEFAULT NULL, salt varchar(50) DEFAULT NULL, email varchar(100) DEFAULT NULL, type int(11) DEFAULT NULL COMMENT '0-普通用户; 1-超级管理员; 2-版主;', status int(11) DEFAULT NULL COMMENT '0-未激活; 1-已激活;', activation_code varchar(100) DEFAULT NULL, header_url varchar(200) DEFAULT NULL, create_time timestamp NULL DEFAULT NULL, PRIMARY KEY (id), KEY index_username (username(20)), KEY index_email (email(20))) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8; ...

March 20, 2023 · 3 min · jiezi

关于node.js:dirname-filename-pathresolve-pathjoin-processcwd

MasOs零碎,在终端中, /Users/a1234/Desktop/ 目录下,执行命令 node script/demo.js \# __dirname - 返回以后模块的目录名console.log(__dirname); >>> /Users/a1234/Desktop/script输入后果: 以后文件所在目录的绝对路径 \# __filename - 返回以后模块文件的文件名,蕴含绝对路径console.log(__filename); >>> /Users/a1234/Desktop/script/demo.js输入后果: 以后文件的绝对路径 \# path.resolve() - 解析门路,返回绝对路径console.log(path.resolve()); >>> /Users/a1234/Desktopconsole.log(path.resolve('./demo.js')); >>> /Users/a1234/Desktop/demo.jsconsole.log(path.resolve(__dirname, './demo.js')); >>> /Users/a1234/Desktop/script/demo.js输入后果: Node.js 过程当前工作的目录 + 传入参数(相对路径)的组合 \# path.join() - 拼接门路,返回拼接后的门路console.log(path.join()); >>> .console.log(path.join('./demo.js')); >>> demo.jsconsole.log(path.join(__dirname, './demo.js')); >>> /Users/a1234/Desktop/script/demo.js输入后果: 传入参数(相对路径)的组合 \# process.cwd() - 返回 Node.js 过程当前工作的目录console.log(process.cwd()); >>> /Users/a1234/Desktop输入后果: Node.js 过程当前工作的目录 ! 总结优先应用 path.resolve;能够适配绝大多数场景;

March 15, 2023 · 1 min · jiezi

关于node.js:expressjs源码阅读笔记

express 实质上就是一个封装过的http.createServer的回调函数express中次要有以下几个外围概念 applicationrouterroutelayer每一个application上会有一个router实例,这个router实例会是application的一个属性且是单例的,会在特定场景初始化,例如app.use、app.get等办法初始化。app.use、app.get等办法实质上最终还是会调用到application上的router实例上对应的办法,比方app.use其实是调用router实例上的use办法、app.get其实是调用router实例上的route办法。router实例上有一个stack属性,是数组类型,用来寄存一个个layer实例layer的次要最作用就是用来存储一个门路path和门路对应的申请处理函数fn。通过app.use(fn)(也就是router.use(fn)),能够创立的一个layer,对应的path是/,fn就是传入的函数通过router.route(path)也能够创立一个layer,对应的path是/,layer存储是route.dispatch.bind(route),route就是后面创立的route实例。router.route(path)会把创立的route实例return进来,能够看上面的代码辅助了解app.route('/list').get((req, res) => { res.end('hello get'); }).post((req, res) => { res.end('hello post'); }).put((req, res) => { res.end('hello put'); }).delete((req, res) => { res.end('hello delete'); });route实例上也有一个stack属性,同样是数组类型,寄存的也是layer。通过调用route实例裸露进去的办法,就会创立一个layer,例如app.route('/list').get((req, res) => { res.end('hello get'); })上述代码会在router创立的route里,再创立一个layer保留get(fn)中的fn函数 route实例上的layer,对应的path都是/,但因为route也有path属性,所以能够了解route上的layer对应的path是route.path + '/'依据layer存储地位的不同,能够把一个express app分为两层 存储在router上的layer形成的中间件层存储在route上的layer形成的路由层路由层能够看做是中间层的上司层级。 中间件层的layer,有两种类型,一种有route属性,一种没有route属性,有route属性的layer上,能够通过layer.route找到对应的路由层。当一个申请拜访到express app对应的server时,会调用app.handle办法,在app.handle中调用router.handle,在router.handle中会遍历中间件层的layer,取出每一个layer进行解决,如果layer上有route属性,会进入到route对应的路由层去解决这一层的所有layer,解决实现之后,再回到上一层layer

March 15, 2023 · 1 min · jiezi

关于node.js:cligetter|一款快速生成-Cli工具-开发模版的脚手架

概述近年来 cli工具 的开发,对于一直倒退的前端生态来说,仿佛也逐步成为工程师们的必备技能。其实开发一个 cli工具 并不难,但对于前端的同学可能存在一点认知上的小门槛,特地是对于刚开始接触 cli 脚手架工具开发的同学来说,如何搭建一个 cli 的开发环境还是挺让人抓狂的。 明天要介绍的工具能够让咱们间接跳过这个门槛,专一于开发 cli 的性能,它就是 cligetter。 装置npm install cligetter -g应用cligetter 的应用特地简略,目前提供了两套 cli 开发模版,blank 和 cac blank 会创立一个空模版,应用 tsc 提供 ts 反对,是一个极简的 cli 开发环境cac 会创立一个基于 CAC 开发模版,应用 rollup 进行编译构建来解决应用 esm 时 commonjs 上下文缺失的问题 应用模版创立一个 cli 我的项目能够应用 new 命令来创立一个新的 cli 我的项目 cligetter new <projectName>这里咱们创立一个名为 my-cli 的工程,并指定为 cac 模版 cligetter new my-cli --template=cac或者简写为: cligetter new my-cli -t cac启动开发环境在控制台执行生成命令后咱们失去以下提醒,那么接下来依照程序执行即可 入口文件我的项目构造如图所示,scripts/index.ts 为我的项目的入口文件,模版中曾经应用 cac 编写好了一个指令的样例 测试模版内置的指令执行指令咱们能够在我的项目目录下关上终端,输出 node ./bin/cli.js log hello-world能够看到胜利执行了 log 指令并在控制台输入了 log信息 ...

March 10, 2023 · 1 min · jiezi

关于node.js:express源码分析1express实例的构造函数

这篇文章是express源码浏览系列文章的第一篇,这个系列的文章次要目标是想从一个Node.js的初学者的视角,联合express的API文档去剖析解读express这个热门库的实现原理。 express的入口从使用者的角度来看,express的入口应该是: const express = require('express');通过express仓库的package.json以及index.js能够看出,express整体的入口位于./lib/express。如下图 ./lib/express次要蕴含以下几个局部: express实例的构造函数:createApplicationexpress提供的实例对象:application、request、responseexpress提供的路由性能: Router,Routeexpress默认反对的middlewares: express.json()、express.query()等这几个局部基本上能够和express的API文档对应起来 2、3、4局部次要就是简略的赋值导出,不做过多的剖析express实例的构造函数通常在应用express的时候会呈现以下代码: const express = require('express');const app = express();而后面提到的createApplication就是对应咱们调用的express(). function createApplication() { var app = function(req, res, next) { app.handle(req, res, next); }; mixin(app, EventEmitter.prototype, false); mixin(app, proto, false); // expose the prototype that will get set on requests app.request = Object.create(req, { app: { configurable: true, enumerable: true, writable: true, value: app } }) // expose the prototype that will get set on responses app.response = Object.create(res, { app: { configurable: true, enumerable: true, writable: true, value: app } }) app.init(); return app;}express实例的类型createApplication的返回值是一个function,而且是在express应用中很常见的listener ...

March 9, 2023 · 1 min · jiezi

关于node.js:Nodejs学习二

1.应用Nodejs来一打C++扩大学习,到3.6.3中应用Persistent 句柄的中央,依照书中代码应用MarkIndependent函数会报错。Persistent类曾经没有该办法了,搜寻正在应用的node 14版本的git源码,发现了commit log中有相干记录.查看对应commit记录https://github.com/nodejs/node/commit/80c46c1576得出结论。

March 8, 2023 · 1 min · jiezi

关于node.js:详解MyBatis中Executor执行SQL语句的过程

前言在详解MyBatis的SqlSession获取流程文章中曾经晓得,MyBatis中获取SqlSession时会创立执行器Executor并存放在SqlSession中,通过SqlSession能够获取映射接口的动静代理对象,动静代理对象的生成能够参考详解MyBatis加载映射文件和动静代理,能够用下图进行概括。 所以,映射接口的动静代理对象理论执行办法时,执行的申请最终会由MapperMethod的execute() 办法实现。从MapperMethod的execute() 办法开始,后续执行流程,能够用下图进行示意。 本篇文章将以MapperMethod的execute() 办法作为终点,对MyBatis中的一次理论执行申请进行阐明,并联合源码对执行器Executor的原理进行阐释。本篇文章不会对MyBatis中的缓存进行阐明,对于MyBatis中的一级缓存和二级缓存相干内容,会在后续的文章中独自进行剖析,为了屏蔽MyBatis中的二级缓存的烦扰,须要在MyBatis的配置文件中增加如下配置以禁用二级缓存。<settings> <setting name="cacheEnabled" value="false"/></settings>复制代码MyBatis版本:3.5.6注释本节将以一个理论的查问例子,以单步跟踪并联合源码的办法,对MyBatis的一次理论执行申请进行阐明。给定映射接口如下所示。public interface BookMapper { Book selectBookById(int id);}复制代码给定映射文件如下所示。<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.mybatis.learn.dao.BookMapper"> <resultMap id="bookResultMap" type="com.mybatis.learn.entity.Book"> <result property="bookName" column="b_name"/> <result property="bookPrice" column="b_price"/></resultMap><select id="selectBookById" resultMap="bookResultMap"> SELECT b.id, b.b_name, b.b_price FROM book b WHERE b.id=#{id}</select></mapper>复制代码MyBatis的执行代码如下所示。public class MybatisTest { public static void main(String[] args) throws Exception { String resource = "mybatis-config.xml"; SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder() .build(Resources.getResourceAsStream(resource)); // 获取SqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); // 获取映射接口的动静代理对象 BookMapper bookMapper = sqlSession.getMapper(BookMapper.class); // 执行一次查问操作 System.out.println(bookMapper.selectBookById(1));}}复制代码基于上述的映射接口,映射文件和执行代码,最终执行查问操作时,会调用到MapperMethod的execute() 办法并进入查问的逻辑分支,这部分源码如下所示。public Object execute(SqlSession sqlSession, Object[] args) { ...

March 7, 2023 · 3 min · jiezi

关于node.js:Nodejs-未来发展趋势

作者:京东批发 郑炳懿 前言当下,Node.js 作为一种异步 I/O 和事件驱动编程的语言,在前端和后端畛域都具备很高的遍及度。同时,Node.js 作为一个底层运行时环境,使得开发者能够轻松地构建出高性能、可扩大和可保护的应用程序。 Node.js 是一种十分有前途的后端技术,它具备高性能、高可扩展性和轻量级等长处。Node.js 还能够用来开发命令行工具和跨平台桌面应用程序等,具备十分宽泛的利用场景。随着前后端拆散和全栈开发模式的衰亡,Node.js 也成为了前端开发的重要技术之一。 在本文中,咱们将从Node.js 优劣势比照、零碎架构、对前端影响三个层面深入分析,以及对将来行业发展趋势的一些预测进行探讨。 Node.js 的优劣势首先,要理解Node.js 具备什么样的能力,得先理解node.js 都具备那些优劣势,只有相熟开发语言的优劣势,能力在应用它的时候更好的利用劣势,避开劣势。 Node.js 劣势:高效的异步 I/O 模型:Node.js 的事件驱动和异步 I/O 模型使得它可能在解决高并发和 I/O 密集型工作时表现出色。基于 JavaScript 的对立语言:Node.js 应用 JavaScript 作为开发语言,使得前端和后端开发都能够应用同一种语言进行开发,从而进步了开发效率和代码可维护性。丰盛的模块库:Node.js 的生态系统十分丰盛,领有大量的第三方模块,使得开发者能够疾速构建出各种类型的利用。轻量级和易于部署:Node.js 采纳模块化开发方式,使得应用程序能够轻松地分解成小模块,从而进步了可维护性和可扩展性。同时,Node.js 的应用程序能够轻松地部署到各种云端平台上。Node.js 劣势:CPU 密集型工作体现不佳:因为 Node.js 的单线程模型,当须要进行大量的 CPU 密集型计算时,会呈现性能瓶颈,导致程序的运行效率降落。可靠性不如传统后端语言:因为 Node.js 的绝对年老和疾速迭代,它在可靠性和稳定性方面绝对传统后端语言可能还有肯定的差距。不足成熟的企业级反对:绝对于其余后端语言,Node.js 在企业级反对和服务方面还不够成熟,例如安全性、稳定性、可靠性等方面的反对还须要进一步增强。克服劣势的一些措施:应用 Node.js 的多过程模式:Node.js 能够应用多过程模式来充分利用多个 CPU 外围的解决能力,进步应用程序的性能。抉择适宜的开发工具和框架:抉择适宜的开发工具和框架能够帮忙咱们更轻松地解决类型检查和谬误提醒等问题,进步开发效率和代码品质。进行性能优化:对于须要进行大量计算的工作,咱们能够应用 C++ 插件或其余语言编写的插件来进步 Node.js 的解决能力。应用 TypeScript:TypeScript 是 JavaScript 的一个超集,它提供了弱小的类型检查和谬误提醒性能,能够帮忙咱们编写更平安、可保护的代码。// 传统的同步形式const fs = require('fs');const data = fs.readFileSync('/path/to/file');console.log(data);// 应用异步形式const fs = require('fs');fs.readFile('/path/to/file', (err, data) => { if (err) throw err; console.log(data);});// 应用缓存技术进步性能const cache = {};function fetchData(id, callback) { if (cache[id]) { callback(cache[id]); } else { fetch(id, (result) => { cache[id] = result; callback(result); }); }}// 应用多过程模式进步性能const cluster = require('cluster');const os = require('os');if (cluster.isMaster) { for (let i = 0; i < os.cpus().length; i++) { cluster.fork(); }} else { // 子过程的代码}// 应用 PM2 进行过程治理和监控// npm install pm2 -g// pm2 start app.js// pm2 list// pm2 monit// pm2 stop app// 应用 Node.js 的性能监控工具const { performance } = require('perf_hooks');const t0 = performance.now();// do some workconst t1 = performance.now();console.log(`Time elapsed: ${t1 - t0} ms`);Node.js 作为零碎架构Node.js是一款基于Chrome V8引擎构建的JavaScript运行时环境,可用于服务器端利用程序开发。它提供了一种疾速、可扩大的形式来解决后端逻辑,并且曾经成为古代Web利用程序开发的重要组成部分。 ...

March 6, 2023 · 3 min · jiezi

关于node.js:它来啦它来啦ChatGPT35-API正式上线且看如何使用nodejs接入chatgpt

介绍 OpenAI发表正式上线了GPT3.5 API,咱们日常应用的chatGPT这个是用这个模型提供的。 依照文档提醒你能够基于这个API实现相似上面的性能: 编写电子邮件或其余文章编写代码答复问题 ....也能够基于这个API去实现你的利用,比方AI聊天机器人之类的 如何接入ChatGPT API身为一个前端工程师,接下来就用nodejs来演示如何接入ChatGPT API API调用官网有提供http接口能够间接让你用api调用,这个没啥说的,充钱,调就是了! NPM包openai-node地址: https://github.com/openai/openai-node 官网有提供对应的NPM包,封装了Http接口调用,以及入参出参的TS类型提醒,应用起来很不便。 const { Configuration, OpenAIApi } = require("openai");const configuration = new Configuration({ apiKey: process.env.OPENAI_API_KEY,});const openai = new OpenAIApi(configuration);const completion = await openai.createCompletion({ model: "text-davinci-003", prompt: "Hello world",});console.log(completion.data.choices[0].text);不过目前不反对尚不反对流式解决 (stream=true),如果有这个须要,须要自行解决 chatgpt-api地址: https://github.com/transitive-bullshit/chatgpt-api 这是一个第三方封装的npm包,用法和官网相似,并反对stream模式。也反对命令行调用 import { ChatGPTAPI } from 'chatgpt'async function example() { const api = new ChatGPTAPI({ apiKey: process.env.OPENAI_API_KEY }) const res = await api.sendMessage('Hello World!') console.log(res.text)}费用gpt-3.5-turbo模型的费用为 $0.002 / 1K tokens,这费用仅仅只有老模型的十分之一,大大利好各位API BOY的调用 ...

March 3, 2023 · 1 min · jiezi

关于node.js:xcrawl-一个新的-Nodejs-多功能爬虫库

x-crawlx-crawl 是新的 Nodejs 多功能爬虫库。 特色只需简略的配置即可抓取页面、JSON、文件资源等等。内置 puppeteer 爬取页面 ,并用采纳 jsdom 库对页面解析。反对 异步/同步 形式爬取数据。反对 Promise/Callback 形式获取后果。轮询性能,定点爬取。拟人化的申请间隔时间。应用 TypeScript 编写,提供泛型。跟 puppeteer 的关系fetchPage API 外部应用 puppeteer 库来爬取页面。 能够实现以下操作: 生成页面的屏幕截图和 PDF。抓取 SPA(单页应用程序)并生成预渲染内容(即“SSR”(服务器端渲染))。自动化表单提交、UI 测试、键盘输入等。示例每隔一天就获取 bilibili 国漫主页的轮播图片为例: // 1.导入模块 ES/CJSimport xCrawl from 'x-crawl'// 2.创立一个爬虫实例const myXCrawl = xCrawl({ timeout: 10000, // 申请超时工夫 intervalTime: { max: 3000, min: 2000 } // 管制申请频率})// 3.设置爬取工作// 调用 startPolling API 开始轮询性能,每隔一天会调用回调函数myXCrawl.startPolling({ d: 1 }, () => { // 调用 fetchPage API 爬取 HTML myXCrawl.fetchPage('https://www.bilibili.com/guochuang/').then((res) => { const { jsdom } = res.data // 默认应用了 JSDOM 库解析 HTML // 获取轮播图片元素 const imgEls = jsdom.window.document.querySelectorAll('.carousel-wrapper .chief-recom-item img') // 设置申请配置 const requestConfig = [] imgEls.forEach((item) => requestConfig.push({ url: `https:${item.src}` })) // 调用 fetchFile API 爬取图片 myXCrawl.fetchFile({ requestConfig, fileConfig: { storeDir: './upload' } }) })})运行成果: ...

March 3, 2023 · 1 min · jiezi

关于node.js:day24nodejs基础

day24-nodejs根底一、nodejs介绍 1.简介 nodejs是一个软件,提供了js的运行环境2.nodejs应用注意事项 没有window、document,不须要写dom和bom,只剩下ECMAScript3.nodejs运行 命令行中node进入控制台node js文件名称二、简略命令 盘符:----------进入某个盘符 cd /d 目录: ----------进入某个目录cd .. ----------回到上一级dir ----------查看以后文件夹中的所有文件和文件夹tree ----------查看以后文件夹中的所有文件和文件夹包含子文件夹及其文件,树状构造cls----------清屏ipconfig ----------查看以后电脑的网管信息systeminfo ----------查看以后电脑的配置信息md 文件夹名字 ----------新建文件夹rd 文件夹名字 ----------删除文件夹type nul> 文件名 ----------新建文件echo 内容 > 文件名 ----------给文件中写入内容ren 文件名 新文件名 ----------将文件重命名del 文件名 ----------删除一个文件三、模块化开发 1.IIFE---伪模块开发 解决了全局净化的问题 无奈解决文件依赖问题2.AMD 解决了文件依赖关系的问题 首屏加载很慢,后续操作很晦涩3.CMD 实现了文件的按需加载,首屏加载很快 后续操作不是很晦涩 4.ES6---*** 运行在服务器环境中 script标签必须有 type='module'属性 向外共享模块成员用export关键字 导入其余模块成员用import关键字 默认导出语法:export default 默认导出的成员----每个模块只容许应用一次export default 默认导入语法: import 承受名称 from '模块标识符' 按需导出语法:export 按需导出的成员 按需导入语法:import {xxx} from '模块标识符' export var a = '小狗'--这种导出用import {解构} from '文件'或者用import * as 对象 from '文件'5.CommonJs标准---***** 只实用于nodejs 导出:module.exports = 数据 ----exports.键 = 值 留神:不能给exports赋值 导入:require('文件门路')---后缀能够省略,./不能省略四、内置模块 ...

March 2, 2023 · 2 min · jiezi

关于node.js:通过-ChatGPT-做一个终端对话玩具xx再也不怕我xx了

疏导篇从去年12月初理解到 ChatGPT,也注册了账号,然而始终没去应用(真是太懒了)。 置信大家就算没应用过,也听闻过它的传说,简略来说就是一个解答性聊天机器人。 最近呢,有几位敌人也始终在向我征询一些 ChatGPT 的问题,想了想还是做个小利用,带各位来理解并应用上ChatGPT。 申明一下,此篇文章真不是用 ChatGPT 生成的。注册篇曾经有很多大佬来介绍这个注册形式了,我简略的说一下步骤吧。 筹备好迷信上网的节点(香港、越南的不行);在 https://sms-activate.org/ 验证码平台上充值个1$;去 https://chat.openai.com/auth/login 通过邮箱注册(举荐谷歌间接注册);在验证码平台上找一个 openai 的验证码服务(最便宜的是印尼的,有效期20分钟);输出验证码平台上的手机号进行验证;期待验证码呈现,粘贴之后即可实现注册;能够间接在 https://platform.openai.com/account/api-keys 生成 apiKey;实战篇本次做的小工具,是一个终端对话助手。通过用户的输出内容,让 ChatGPT 进行辨认答复并输入。 效果图 筹备工作初始化 yarn init -y装置插件 openai(对话性能)inquirer(解决命令行输出等操作)cli-spinner(Loading成果)筹备 openai 的 apiKey 对接 OpenAI引入 openai,并且写一个调用入口函数。 const { Configuration, OpenAIApi } = require("openai");async function main() { // 创立 openai 配置 const configuration = new Configuration({ apiKey: 'apiKey' }); // 初始化 openai const openai = new OpenAIApi(configuration); const { data: { choices } } = await openai.createCompletion({ model: 'text-davinci-003', // 对话机器人模型 prompt: 'js 是什么?', // 问题 temperature: 0.5, // 准确性的概率,0是最精准的 max_tokens: 150, // 输入内容长度 top_p: 1.0, // 防止反复和不相干的内容 frequency_penalty: 0.0, // 管制语言模型中呈现的词语频率,惩办 presence_penalty: 0.0, // 管制语言模型中呈现的词语频率,惩办 }) console.log(choices[0].text); // 输入的内容}main()输入的后果如下图 ...

March 1, 2023 · 3 min · jiezi

关于node.js:Nodejs-学习笔记一

1.先从Nodejs的入口谈起,一下采纳的是nodejs 6.9.4 版本。nodejs启动的入口文件src/node_main.cc // UNIXint main(int argc, char *argv[]) { // Disable stdio buffering, it interacts poorly with printf() // calls elsewhere in the program (e.g., any logging from V8.) setvbuf(stdout, nullptr, _IONBF, 0); setvbuf(stderr, nullptr, _IONBF, 0); return node::Start(argc, argv);}由代码可看出,次要运行的是node::Start办法,此办法定义在src/node.cc文件中。 int Start(int argc, char** argv) { PlatformInit(); CHECK_GT(argc, 0); // Hack around with the argv pointer. Used for process.title = "blah". argv = uv_setup_args(argc, argv); // This needs to run *before* V8::Initialize(). The const_cast is not // optional, in case you're wondering. int exec_argc; const char** exec_argv; Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);#if HAVE_OPENSSL#ifdef NODE_FIPS_MODE // In the case of FIPS builds we should make sure // the random source is properly initialized first. OPENSSL_init();#endif // NODE_FIPS_MODE // V8 on Windows doesn't have a good source of entropy. Seed it from // OpenSSL's pool. V8::SetEntropySource(crypto::EntropySource);#endif v8_platform.Initialize(v8_thread_pool_size); V8::Initialize(); int exit_code = 1; { NodeInstanceData instance_data(NodeInstanceType::MAIN, uv_default_loop(), argc, const_cast<const char**>(argv), exec_argc, exec_argv, use_debug_agent); StartNodeInstance(&instance_data); exit_code = instance_data.exit_code(); } V8::Dispose(); v8_platform.Dispose(); delete[] exec_argv; exec_argv = nullptr; return exit_code;}此办法开端处调用了同一个文件中的StartNodeInstance办法,传入一个NodeInstanceData(node_internals.h中定义)实例,在这个办法中调用了LoadEnvironment办法,LoadEnvironment办法有如下代码: ...

February 28, 2023 · 3 min · jiezi

关于node.js:Mac上最简单配置多版本Nodejs环境

背景Nodejs版本更新十分迅速,截止目前(2023年2️)曾经更新到了19.17.0,笔者查了下官网列出的历史版本,足足有73页之多。而咱们常常须要保护一些多年前的旧我的项目,因为一些依赖的起因导致最新版本的Node不肯定兼容,所以也就呈现了咱们须要依据我的项目去切换Node版本的问题了。 装置Nodejs笔者应用的是Mac零碎,本文将以Mac操作系统为例进行多版本Nodejs的装置。首先,拜访Nodejs官网,下载最新版本的Nodejs,官网会主动依据咱们的零碎来下载对应的安装包。倡议下载LTS版本,也就是长期反对版,稳定性更好一些。下载好后间接装置,基本上始终点击持续就能够了。装置好后,能够关上终端,输出node --version, 输出后如果显示了咱们装置的Nodejs版本号,则示意曾经装置胜利。 切换其余Nodejs版本怎么切换其余的Nodejs版本呢,这时候就须要一个npm包来实现了,它就是n,咱们能够用npm命令装置它 sudo npm i -g n留神:n也是一个命令行程序,Mac上如果须要用npm装置一些全局命令的包,须要加上sudo以应用管理员权限。装置好后咱们能够应用n ls查看以后曾经装置了的node版本:假如笔者须要再装置一个Node.js的16.13.0的版本,咱们能够应用如下命令: sudo n install 16.13.0装置胜利成果如下:这时候,咱们的node版本曾经切换到16.13.0了,咱们能够持续应用node --version 验证如果咱们须要再切换回原来的18.14.1怎么办呢?其实也简略。间接输出sudo n, 会呈现一个选项式的交互式命令行让咱们抉择切换的版本,咱们通过按高低箭头键抉择18.14.1就行了,而后按enter键即可切换,十分的简略不便。n是一个命令行程序,咱们能够应用 n --help 查看更多该命令的用法,这里就不再赘述了。

February 26, 2023 · 1 min · jiezi

关于node.js:将nodejs-应用构建成dokcer镜像

本文内容:将node.js 利用构建成dokcer镜像, 并上传到阿里云 创立 Node.js 利用1.首先,创立一个 package.json 文件,形容你应用程序以及须要的依赖:{ "name": "pack_docker", "version": "1.0.0", "description": "Node.js on Docker", "author": "weiweiyi", "main": "pack.js", "dependencies": { "dingtalk-robot-sender": "^1.2.0", "compressing": "^1.7.0", "node-ssh": "13.0.1" }}2.运行 npm install这会主动生成一个 package-lock.json 文件,将其拷贝进入接下来的 Docker 镜像中。 3.将你须要运行或者寄存的node.js文件放在本目录下创立 Dockerfile 文件创立一个空文件,命名为 Dockerfile:touch Dockerfile 编写该文件 # 指定node 版本FROM node:14.16.0# 工作目录WORKDIR /root/# 复制文件COPY package*.json ./# 装置依赖RUN npm install# 拷贝应用程序COPY pack.js .# 也能够抉择,间接运行该js文件# CMD [ "node", "pack.js" ]创立.dockerignore文件 和 .gitignore文件防止 node_modules 被拷贝到docker image中。 /node_modules 创立docker image创立命令: ...

February 14, 2023 · 1 min · jiezi

关于node.js:基于nodejs-自动打包项目并提供http下载

前言需要是:当 gitlab 我的项目,新建tag公布时。通过脚本主动打包成压缩包,并提供http下载。使得我的项目公布新版本时,用户可能通过url间接下载 流程图: 服务器配置目前用于实现http服务的软件有许多,包含支流的Apache、Nginx,还有微软的IIS等。这里应用apache。 在学习HTTP协定的时候,咱们晓得URL实际上指定的就是服务器上特定的文件,所以应用apche中的httpd这个轻量的HTTP server实现一个简略的文件下载服务是再适合不过的了。 1.装置apt-get install apache2若有子包抉择,则抉择httpd 2.启动 /etc/init.d/apache2 start 3.查看启动状态:/etc/init.d/apache2 status 4.尝试拜访而后,拜访服务器的公网ip或域名,就能够看到相似如下界面,此时阐明Apache失常工作:若须要更改端口, 能够看这篇 批改apache2端口 5.下载 最初在 /var/www/html 门路下,删除 index.html,上传本人想要被下载的文件,再次拜访,就能够进行下载了。 若不想所有人都能够通过该url拜访到服务器,还能够加上账号密码验证,能够参考账号密码验证 最初,能够通过 域名/文件名 的形式间接给他人一个链接,进行下载。 例如:xxxxx.com:port/20230214_myTestProject.zip, 拜访该url就能够下载。 脚本开发首先须要借助 gitlab 的 CI/CD GitLab CI/CDCI ( Continuous Integration) ,中文即继续集成。CD ( Continuous Delivery / Continuous Deployment) 继续交付 或 继续布署。官网文档 首先须要装置gitlab-runner,官网装置文档 编写.gitlab-ci.yml设置执行规定 workflow: # 当有tag或merge request时执行 rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event" || $CI_COMMIT_TAG != null'# 设置步骤(步骤间串行)stages: - pack-web命令行写法最开始我是通过间接命令行的模式编写: ...

February 14, 2023 · 4 min · jiezi

关于node.js:只改了五行代码接口吞吐量提升了10多倍

背景公司的一个ToB零碎,因为客户应用的也不多,没啥并发要求,就始终没有通过压测。这两天来了一个“大客户”,对并发量提出了要求:外围接口与几个重点应用场景单节点吞吐量要满足最低500/s的要求。过后一想,500/s吞吐量还不简略。Tomcat依照100个线程,那就是单线程1S内解决5个申请,200ms解决一个申请即可。这个没有问题,平时接口响应工夫大部分都100ms左右,还不是分分钟满足的事件。然而压测一开,100 的并发,吞吐量竟然只有 50 ... 而且再一查,100的并发,CPU使用率竟然靠近 80% ... 从上图能够看到几个重要的信息。最小值: 示意咱们非并发场景单次接口响应时长。还有余100ms。挺好!最大值: 并发场景下,因为各种锁或者其余串行操作,导致局部申请期待时长减少,接口整体响应工夫变长。5秒钟。有点过分了!!!再一看百分位,大部分的申请响应工夫都在4s。无语了!!!所以 1s钟的 吞吐量 单节点只有 50 。间隔 500 差了10倍。 好受!!!!剖析过程定位“慢”起因 这里临时先疏忽 CPU 占用率高的问题 首先均匀响应工夫这么慢,必定是有阻塞。先确定阻塞地位。重点查看几处: 锁 (同步锁、分布式锁、数据库锁)耗时操作 (链接耗时、SQL耗时) 联合这些先配置耗时埋点。 接口响应时长统计。超过500ms打印告警日志。接口外部近程调用耗时统计。200ms打印告警日志。Redis拜访耗时。超过10ms打印告警日志。SQL执行耗时。超过100ms打印告警日志。 上述配置失效后,通过日志排查到接口存在慢SQL。具体SQL相似与这种:<!-- 次要相似与库存扣减 每次-1 type 只有无限的几种且该表一共就几条数据(一种一条记录)--><!-- 压测时能够认为 type = 1 是写死的 -->update table set field = field - 1 where type = 1 and filed > 1;复制代码上述SQL相当于并发操作同一条数据,必定存在锁期待。日志显示此处的期待耗时占接口总耗时 80% 以上。二话不说先改为敬。因为是压测环境,间接改为异步执行,确认一下成果。PS:过后心里是这么想的: 妥了,功败垂成。就是这里的问题!绝壁是这个起因!优化一下就解决了。当然,如果这么简略就没有必要写这篇文章了...优化后的成果: 嗯...emm...好! 这个优化还是很显著的,晋升晋升了近2倍。 此时曾经感觉到有些不对了,慢SQL曾经解决了(异步了~ 轻易吧~ 你执行 10s我也不论了),尽管对吞吐量的晋升没有预期的成果。然而数据是不会骗人的。最大值: 曾经从 5s -> 2s百分位值: 4s -> 1s这曾经是很大的晋升了。持续定位“慢”的起因通过第一阶段的“优化”,咱们间隔指标近了很多。废话不多说,持续下一步的排查。咱们持续看日志,此时日志呈现相似下边这种状况:2023-01-04 15:17:05:347 INFO ....50 [TID: 1s22s72s8ws9w00] *2023-01-04 15:17:05:348 INFO ....21 [TID: 1s22s72s8ws9w00] *2023-01-04 15:17:05:350 INFO ....47 [TID: 1s22s72s8ws9w00] * ...

February 14, 2023 · 2 min · jiezi

关于node.js:聊透Spring-bean的生命周期

在对于Spring的所有解读中,Bean的生命周期都堪称是重中之重,甚至还有人称Spring就是个治理Bean的容器。Bean的生命周期之所以这么重要,被重复提及,是因为Spring的外围能力,比方对象创立(IOC)、属性注入(DI)、初始化办法的调用、代理对象的生成(AOP)等性能的实现,都是在bean的生命周期中实现的。分明了bean的生命周期,咱们能力晓得Spring的神奇魔法到底是什么,是怎么一步步赋能,让本来一般的java对象,最终变成领有超能力的bean的。 bean的生命周期 Spring的生命周期大抵分为:创立 -> 属性填充 -> 初始化bean -> 应用 -> 销毁 几个外围阶段。咱们先来简略理解一下这些阶段所做的事件:创立阶段次要是创建对象,这里咱们看到,对象的创立权交由Spring治理了,不再是咱们手动new了,这也是IOC的概念。属性填充阶段次要是进行依赖的注入,将以后对象依赖的bean对象,从Spring容器中找进去,而后填充到对应的属性中去。初始化bean阶段做的事件绝对比较复杂,包含回调各种Aware接口、回调各种初始化办法、生成AOP代理对象也在该阶段进行,该阶段次要是实现初始化回调,前面咱们缓缓剖析。应用bean阶段,次要是bean创立实现,在程序运行期间,提供服务的阶段。销毁bean阶段,次要是容器敞开或进行服务,对bean进行销毁解决。 当然,bean的生命周期中还包含其余的流程,比方裸露工厂对象等,只是相对而言都是为其余性能做伏笔和筹备的,再讲到对应性能时,咱们在做详细分析。1.1 创立bean 对象的创立是bean生命周期的第一步,毕竟要先有1能力有0嘛。创建对象的形式有很多,比方 new、反射、clone等等,Spring是怎么创建对象的呢?绝大多数状况下,Spring是通过反射来创建对象的,不过如果咱们提供了Supplier或者工厂办法,Spring也会间接应用咱们提供的创立形式。 咱们从源码登程,看一下Spring是如何抉择创立形式的:// 源码位于 AbstractAutowireCapableBeanFactory.javaprotected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // 再次解析BeanDefinition的class,确保class曾经被解析 Class<?> beanClass = resolveBeanClass(mbd, beanName); // 1: 如果提供了Supplier,通过Supplier产生对象 Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName);} // 2: 如果有工厂办法,应用工厂办法产生对象 // 在@Configration配置@Bean的办法,也会被解析为FactoryMethod if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args);} //...省略局部代码 // 3: 推断构造方法 // 3.1 执行后置处理器,获取候选构造方法 Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); // 3.2 须要主动注入的状况 if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || ...

February 14, 2023 · 3 min · jiezi

关于node.js:90的Java开发人员都会犯的5个错误

前言作为一名java开发程序员,不晓得大家有没有遇到过一些匪夷所思的bug。这些谬误通常须要您几个小时能力解决。当你找到它们的时候,你可能会默默地骂本人是个傻瓜。是的,这些可笑的bug基本上都是你疏忽了一些基础知识造成的。其实都是很低级的谬误。明天,我总结一些常见的编码谬误,而后给出解决方案。心愿大家在日常编码中可能防止这样的问题。 应用Objects.equals比拟对象这种办法置信大家并不生疏,甚至很多人都常常应用。是JDK7提供的一种办法,能够疾速实现对象的比拟,无效防止烦人的空指针查看。然而这种办法很容易用错,例如:Long longValue = 123L;System.out.println(longValue==123); //trueSystem.out.println(Objects.equals(longValue,123)); //false复制代码为什么替换==为Objects.equals()会导致不同的后果?这是因为应用==编译器会失去封装类型对应的根本数据类型longValue,而后与这个根本数据类型进行比拟,相当于编译器会主动将常量转换为比拟根本数据类型, 而不是包装类型。应用该Objects.equals()办法后,编译器默认常量的根本数据类型为int。上面是源码Objects.equals(),其中a.equals(b)应用的是Long.equals()会判断对象类型,因为编译器曾经认为常量是int类型,所以比拟后果肯定是false。public static boolean equals(Object a, Object b) { return (a == b) || (a != null && a.equals(b));}public boolean equals(Object obj) { if (obj instanceof Long) { return value == ((Long)obj).longValue();}return false;}复制代码晓得了起因,解决办法就很简略了。间接申明常量的数据类型,如Objects.equals(longValue,123L)。其实如果逻辑紧密,就不会呈现下面的问题。咱们须要做的是保持良好的编码习惯。 日期格局谬误在咱们日常的开发中,常常须要对日期进行格式化,然而很多人应用的格局不对,导致呈现意想不到的状况。请看上面的例子。Instant instant = Instant.parse("2021-12-31T00:00:00.00Z");DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault());System.out.println(formatter.format(instant));//2022-12-31 08:00:00复制代码以上用于YYYY-MM-dd格式化, 年从2021 变成了 2022。为什么?这是因为 java 的DateTimeFormatter 模式YYYY和yyyy之间存在轻微的差别。它们都代表一年,然而yyyy代表日历年,而YYYY代表星期。这是一个轻微的差别,仅会导致一年左右的变更问题,因而您的代码本能够始终失常运行,而仅在新的一年中引发问题。12月31日按周计算的年份是2022年,正确的形式应该是应用yyyy-MM-dd格式化日期。这个bug特地荫蔽。这在平时不会有问题。它只会在新的一年到来时触发。我公司就因为这个bug造成了生产事变。在 ThreadPool 中应用 ThreadLocal如果创立一个ThreadLocal 变量,拜访该变量的线程将创立一个线程局部变量。正当应用ThreadLocal能够防止线程平安问题。然而,如果在线程池中应用ThreadLocal ,就要小心了。您的代码可能会产生意想不到的后果。举个很简略的例子,假如咱们有一个电商平台,用户购买商品后须要发邮件确认。private ThreadLocal<User> currentUser = ThreadLocal.withInitial(() -> null);private ExecutorService executorService = Executors.newFixedThreadPool(4); public void executor() { ...

February 8, 2023 · 1 min · jiezi

关于node.js:IntelliJ中高效重构的-10-个快捷方式

前言在日常的开发工作中,咱们常常须要重构,重构能够让咱们写出的代码更上一层楼。所以,我会借助IntelliJ提供的一些性能,帮忙我高效进行重构。这里是我举荐10个快捷方式,也是我每天都在应用的,十分有用。 欢送关注集体公众号【JAVA旭阳】交流学习 1.将抉择提取到局部变量(Ctrl + Alt + V / Cmd + Opt + V)IntelliJ 会倡议一个名称,该名称有时十分离题,有时则不那么离题,但它处于编辑模式。如果您违心,您还能够抉择提取屡次呈现的抉择或仅提取以后抉择。您能够抉择的另一件事作为申明顶部的气泡弹出 — 是否使变量不可变(在本例中为 Kotlin var 或 val)以及可能的其余特定于语言的选项,如上面的 Kotlin 屏幕截图所示 — 是否指定类型。 2.将抉择提取到字段/属性(Ctrl + Alt + F / Cmd + Opt + F)IntelliJ 提供的选项取决于语言,在上面的屏幕截图中 — 是为类定义还是为文件定义。抉择后,您依然能够应用与提取局部变量雷同的选项。 3.提取抉择到一个办法(Ctrl + Alt + M / Cmd + Opt + M)在窗口中,您将看到一旦您点击快捷组合,您就能够控制参数的可见性、程序和名称,当然还有新办法的名称。 4.内联函数(Ctrl + Alt + N / Cmd + Opt + N)这与下面所有 3 个相同——将变量、字段或办法放回它们被应用的中央。同样,您有一些选项,例如内联单次或屡次呈现。 5.挪动到下一个或上一个光标地位(Ctl + Alt + ← 或 → / Cmd + Opt + ← 或 →)这是疾速浏览您编辑的最初几个地位的好办法。6.代码生成(Alt + Insert / Cmd + N)同样,鉴于后果是 上下文 菜单,它取决于上下文,但通常你会用它来生成无聊的位,如equals(), hashCode(), getters 和 setters 或构造函数,实现接口办法等。 ...

February 1, 2023 · 1 min · jiezi

关于node.js:eggjs实战10天入门第2天-项目目录的作用

课程疏导【eggjs实战10天入门-第1天】—— 搭建我的项目【eggjs实战10天入门-第2天】—— controller、service和config(本篇) 本节指标相熟config/router/controller/service各自的作用1、路由(Router)1.1、路由和controller的关系// router.jsmodule.exports = app => { const { router, controller } = app; router.get('/hello', controller.base.index);};// base.jsconst { Controller } = require('egg')class BaseController extends Controller { async index() { this.ctx.body = { data: "hello it's me" } }}module.exports = BaseController再上一节中咱们在router.js中写了这样的代码,他代表的含意就是当用户执行 GET /hello时,app/controller文件夹下的base.js 这个外面的 index 办法就会执行。 那么既然有get办法,必定就有post办法,del办法等。 然而在实在的场景中,咱们必定不会只用/hello这种比拟中二的申请形式。咱们须要接管前端传递过去的参数。比方获取某个id的具体信息,那咱们如何获取参数呢 1.2、参数的传递1.2.1、Query String 形式也就是罕用的xxx?a=1&b=2这种Query传参形式 咱们新增一条路由,/getInfo, 这时当拜访/getInfo时,就会触发base.js的getInfo办法 // app/router.jsmodule.exports = app => { const { router, controller } = app; router.get('/hello', controller.base.index); app.router.get('/getInfo', controller.base.getInfo);};咱们新增一个getInfo办法。当申请走到getInfo函数时,咱们从this中获取ctx,也是本次申请的一个上下文context,外面蕴含着本次申请的数据,如参数,header,中间件挂载的一些罕用数据const { Controller } = require('egg')class BaseController extends Controller { index() { this.ctx.body = { data: "hello it's me" } } getInfo () { const { ctx } = this console.log('ctx.query', ctx.query) ctx.body = { query: ctx.query } }}module.exports = BaseController 当咱们发动申请,http://127.0.0.1:7001/getInfo?a=1&b=1,这时通过ctx.query就能拿到参数对象,{ a: '1', b: '1' }1.2.1、Query String 形式当参数只有一到2个的时候,咱们更趋向于应用 ...

January 17, 2023 · 3 min · jiezi

关于node.js:怎样快速地迁移-MySQL-中的数据

咱们通常会遇到这样的一个场景,就是须要将一个数据库的数据迁徙到一个性能更加强悍的数据库服务器上。这个时候须要咱们做的就是疾速迁徙数据库的数据。那么,如何能力疾速地迁徙数据库中的数据呢?明天咱们就来聊一聊这个话题。数据库的数据迁徙无外乎有两种形式,一种是物理迁徙,另一种则是逻辑迁徙。首先,咱们生成 5 万条测试数据。具体如下:-- 1. 筹备表create table s1( id int, name varchar(20), gender char(6), email varchar(50)); -- 2. 创立存储过程,实现批量插入记录delimiter $$create procedure auto_insert1()BEGIN declare i int default 1;while(i<50000)do insert into s1 values(i,'shanhe','male',concat('shanhe',i,'@helloworld')); set i=i+1; select concat('shanhe',i,'_ok');end while;END$$delimiter ; -- 3. 查看存储过程show create procedure auto_insert1\G -- 4. 调用存储过程call auto_insert1()复制代码逻辑迁徙逻辑迁徙的原理是依据 MySQL 数据库中的数据和表构造转换成 SQL 文件。采纳这一原理罕用的迁徙工具有 mysqldump。上面咱们就来测试一下:[root@dxd ~]# mysqldump -h172.17.16.2 -uroot -pTest123! s1 s1 --result-file=/opt/s1.sql [root@dxd ~]# ll /opt/-rw-r--r-- 1 root root 2684599 5月 10 00:24 s1.sql复制代码咱们能够看到的是,生成了相应的 SQL 。当初咱们通过生成的 SQL 迁徙到另一个数据库中。mysql> use s2;Database changed ...

January 16, 2023 · 3 min · jiezi

关于node.js:微服务-SpringBoot-整合-Redis-GEO-实现附近商户功能

⛄引言本文参考黑马 点评我的项目在点评我的项目中 如何 实现 左近商家的查问呢,展现出间隔本人5公里内的商户,这样的性能如何实现?答案是能够采纳Redis 来实现,当然可能有很多实现形式,本文次要介绍如何应用Redis实现 左近商户的搜寻性能一、Redis GEO 数据结构用法⛅GEO根本语法、指令GEO 就是 GeoLocation 的简写模式,代表地理坐标。Redis在3.2版本中退出了对GEO的反对,容许存储地理坐标信息,帮忙咱们依据经纬度来检索数据。 常见的命令 GEOADD:增加一个天文空间信息,蕴含:经度(longitude)、纬度(latitude)、值(member)GEODIST:计算指定的两个点之间的间隔并返回GEOHASH:将指定member的坐标转为hash字符串模式并返回GEOPOS:返回指定member的坐标GEORADIUS:指定圆心、半径,找到该圆内蕴含的所有member,并依照与圆心之间的间隔排序后返回。6.当前已废除GEOSEARCH:在指定范畴内搜寻member,并依照与指定点之间的间隔排序后返回。范畴能够是圆形或矩形。6.2.新性能GEOSEARCHSTORE:与GEOSEARCH性能统一,不过能够把后果存储到一个指定的key。 6.2.新性能 ⚡应用GEO存储经纬度、查问间隔本篇博文 Redis版本为 6.2版本进入redis 查问 geo相干指令 应用 GEO 实现以下性能 实现两点之间的间隔查问,以及指定范畴内的地点 需要如下 应用 GEO 增加 北京 (天安门 116.397469 39.908821 、故宫 116.397027 39.918056、北海公园 116.389977 39.933144) 经纬度查问 天安门 与 故宫之间的间隔在以上增加的地点中查问 天安门广场 (116.397827 39.90374) 左近2公里的地点 GEOADD 增加 GEOPOS 查看指定地点 经纬度信息 GEOHASH 查看指定地址 经纬度HASH值 拓展: GEOPOS 和 GEOHASH 的区别在于 GEOHASH 节约了 经纬度存储的 内存、缩小不必要的内存耗费,从而晋升性能GEODIST 查看 天安门 与故宫之间的间隔 ...

January 16, 2023 · 2 min · jiezi

关于node.js:Java构建简单的速率限制器

速率限度事实世界中的用户是残忍的,并且没急躁,充斥着各种不确定性。在高并发零碎中,可能会呈现服务器被虚伪申请轰炸的状况,因而您可能心愿管制这种状况。一些理论应用情景可能如下所示: API配额治理-作为提供者,您可能心愿依据用户的付款状况限度向服务器收回API申请的速率。这能够在客户端或服务端实现。安全性-避免DDOS攻打。老本管制--这对服务方甚至客户方来说都不是必须的。如果某个组件以十分高的速率收回一个事件,它可能有助于管制它,它可能有助于管制从客户端发送的遥测。 限速解决时的选项依据咱们解决的申请/事件类型,可能会产生以下状况: 咱们能够放弃额定的申请咱们能够抉择让申请期待,直到零碎将它们升高到预约义的速率。 罕用限速算法 令牌桶算法漏桶算法 咱们将不深刻探讨这些算法的外部细节,因为这超出了本文的范畴。咱们将以令牌桶算法为核心。其要求如下。令牌桶算法基于以固定速率增加令牌的固定容量桶的类比。在容许API持续之前,将查看桶,以查看它过后是否蕴含至多一个令牌。如果令牌存在,则进行API调用。如果不是,则抛弃该音讯/或使其期待。需要 应该可能承受每秒所需的(TPS)事务或速率。如果超过咱们定义的比率,则应放弃交易。应该在同时产生的状况下起作用。 高级性能(在后续文章中实现) 应该可能平滑突发的申请。例如,如果咱们将TPS定义为5,并且所有五个申请都在同一时刻达到,那么它应该可能以固定的工夫距离将它们排成一行,即以200ms的工夫距离执行每个申请。它须要一个外部定时电路。如果咱们的TPS为5,并且在其中一个1秒的时段中,咱们在下一秒只应用3个代币,那么咱们应该可能提供5+2 = 7个代币作为处分。但速率为每个令牌1/7(142.28ms)。奖金不应结转到下一个插槽。 让咱们首先定义咱们的 速率限制器:/** Rate limiter helps in limiting the rate of execution of a piece of code. The rate is defined in terms ofTPS(Transactions per second). Rate of 5 would suggest, 5 transactions/second. Transaction could be a DB call, API call,or a simple function call.<p>Every {@link RateLimiter} implementation should implement either {@link RateLimiter#throttle(Code)} or, {@link RateLimiter#enter()}.They can also choose to implement all.<p>{@link Code} represents a piece of code that needs to be rate limited. It could be a function call, if the code to be rate limitedspreads across multiple functions, we need to use entry() and exit() contract. */public interface RateLimiter { ...

January 16, 2023 · 3 min · jiezi

关于node.js:一个简单的神经网络例子

问题形容咱们的问题是四个人,甲、乙、丙、丁,上面是他们之前去不去看电影的数据: 当初的问题是,如果下次能够确定:甲去、乙去、丙不去,那么丁去的概率是多少? 单节点神经网络咱们的模型如下: x1、x2、x3别离示意甲、乙、丙去不去的值,去就是1,不去是0。输入y示意丁去不去的值。 其中w1、w2、w3别离示意甲、乙、丙的权重,激活函数应用的是sigmoid,也就是: 权重进行随机,而后利用已知的值进行训练,不停调整权重,最终,把须要求解的数据输出获取后果即可。 代码实现// 曾经产生的事件,作为训练种子let seedData = [ // 甲、乙、丙、丁去不去,0示意不去,1示意去 [0, 0, 1, 0], // 第一次 [1, 1, 1, 1], // 第二次 [1, 0, 1, 1], // 第三次 [0, 1, 1, 0] // 第四次];// 甲、乙、丙去不去对丁影响的权重的初始随机值: -1 ~ 1let weights = [Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1];// 循环应用屡次种子进行训练for (let i = 0; i < 10000; i++) { // 每次循环都利用一遍所有的种子 for (let j = 0; j < seedData.length; j++) { // 应用sigmoid激活函数 // y = 1/(1+exp(-x)) let output = 1 / (1 + Math.exp(-1 * (seedData[j][0] * weights[0] + seedData[j][1] * weights[1] + seedData[j][2] * weights[2]))); // 对甲、乙、丙的权重别离进行调整 for (let k = 0; k < 3; k++) { // 而后求解和理论值的差距 let error = seedData[j][3] - output; // 每次求解结束后,依据差距error进行调整权重weights /** * 在这里,调整的幅度取决于“差距”和“后果” * * 1.差距越大,调整的幅度也越大 * 2.对后果而言,output * (1 - output)是一个二次函数,如果后果越凑近0或1,幅度越小,反之越大 */ let delta = error * output * (1 - output); weights[k] += seedData[j][k] * delta; } }}let input = [1, 0, 0];console.log(weights);console.log( 1 / (1 + Math.exp(-1 * (input[0] * weights[0] + input[1] * weights[1] + input[2] * weights[2]))));答疑对于权重调整为什么要乘上输出值的了解?weights[k] += seedData[j][k] * delta;能够看见,权重的调整最终减少的值是seedData[j][k] * delta ...

January 12, 2023 · 1 min · jiezi

关于node.js:你知道微服务架构中的发件箱模式吗

前言微服务架构现在十分的风行,这个架构下可能常常会遇到“双写”的场景。双写是指您的应用程序须要在两个不同的零碎中更改数据的状况,比方它须要将数据存储在数据库中并向音讯队列发送事件。您须要保障这两个操作都会胜利。如果两个操作之一失败,您的零碎可能会变得不统一。那针对这样的状况有什么好的办法或者设计保障呢?本文就和大家分享一个“发件箱模式”, 能够很好的防止此类问题。 欢送关注集体公众号『JAVA旭阳』交换沟通 下订单的例子假如咱们有一个 OrderService 类,它在创立新订单时被调用,此时它应该将订单实体保留在数据库中并向交付微服务发送一个事件,以便交付部门能够开始打算交付。你的代码可能是上面这样子的:@Servicepublic record OrderService( IDeliveryMessageQueueService deliveryMessageQueueService,IOrderRepository orderRepository,TransactionTemplate transactionTemplate) implements IOrderService {@Overridepublic void create(int id, String description) { String message = buildMessage(id, description); transactionTemplate.executeWithoutResult(transactionStatus -> { // 保留订单 orderRepository.save(id, description); }); // 发送音讯 deliveryMessageQueueService.send(message);}private String buildMessage(int id, String description) { // ...}}复制代码能够看到咱们在事务中将订单保留在数据库中,而后咱们应用音讯队列将事件发送到交付服务。这是双写的一个场景。这么写,会遇到什么问题呢?首先,如果咱们保留了订单然而发送音讯失败了怎么办?送货服务永远不会收到音讯。那你可能想到把保留订单和发消息放到同一个事务中不就能够了吗,就是是将 deliveryMessageQueueService#send 挪动到与 orderRepository#save 雷同的事务中,如下图:transactionTemplate.executeWithoutResult(transactionStatus -> { // 保留订单 orderRepository.save(id, description); // 发送音讯 deliveryMessageQueueService.send(message); });复制代码实际上,在数据库事务外部建设 TCP 连贯是一种蹩脚的做法,咱们不应该这样做。有没有更好的办法呢?咱们能够订单表所在的同一数据库中有一个表“发件箱”(在最简略的状况下,它能够有一个列“音讯”和以后工夫戳)。保留订单时,在同一个事务中,咱们在“发件箱”表中保留了一条音讯。音讯一发送,咱们就能够将其从发件箱表中删除,代码如下:@Servicepublic record OrderService( IDeliveryMessageQueueService deliveryMessageQueueService,IOrderRepository orderRepository,IOutboxRepository outboxRepository,TransactionTemplate transactionTemplate) implements IOrderService {@Overridepublic void create(int id, String description) { UUID outboxId = UUID.randomUUID(); String message = buildMessage(id, description); transactionTemplate.executeWithoutResult(transactionStatus -> { // 保留订单 orderRepository.save(id, description); // 保留到发件箱 outboxRepository.save(new OutboxEntity(outboxId, message)); }); deliveryMessageQueueService.send(message); // 删除 outboxRepository.delete(outboxId);}private String buildMessage(int id, String description) { // ...}}复制代码能够看到,咱们在一次事务中将订单和发件箱实体保留在咱们的数据库中。而后咱们发送一条音讯,如果胜利,咱们删除这条音讯。如果 deliveryMessageQueueService#send 失败会怎么?(例如,您的应用程序被终止或音讯队列或数据库不可用)。在这种状况下,outboxRepository#delete 将不会运行,咱们必须重试发送音讯。它能够应用将在后盾运行的打算工作来实现,该工作将尝试发送在表发件箱中显示超过 X 秒(例如 10 秒)的音讯,如上面的代码。@Servicepublic record OutboxRetryTask(IOutboxRepository outboxRepository, ...

January 9, 2023 · 1 min · jiezi

关于node.js:Vue3中name有什么用呢

1.在递归组件的时候须要定义name 2.配合keep-alive include exclude 能够缓存组件 3.在Vue有报错或者调试的时候能够看到组件的name Vue3 定义 name1.主动生成 <script setup> 只有在script开启setup语法糖模式 单文件组件会主动依据文件名生成对应的 name 选项 例如 Tree.vue 那他的name 就是 Tree 主动生成,这样做有一个弊病如果想批改name须要批改组件名称如果有中央import 该组件须要一并批改。 2.在开启一个script用来定义name 长处 这种形式能够随便定义name 弊病 一个单文件组件呈现两个script 会让人感到纳闷。 <template> <div></div> </template> <script lang="ts" setup> import {ref,reactive } from 'vue' </script> <script lang='ts'> export default { name:"XXX" } </script> <style lang="less" scoped> </style> 复制代码 3.应用第三方插件 unplugin-vue-define-options 装置办法 npm i unplugin-vue-define-options -D vite 应用 // vite.config.ts import DefineOptions from 'unplugin-vue-define-options/vite' import Vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [Vue(), DefineOptions()], }) 复制代码 ...

November 30, 2022 · 1 min · jiezi

关于node.js:如何在RHEL-9系统中安装Nodejs

在这篇文章中,咱们将逐渐解释如何在 RHEL 9 零碎上装置 Node.js。 建设在 Google 的 V8 JavaScript 引擎上,Node.js 是收费和开源的,次要用于构建服务器端应用程序。它应用事件驱动和异步模型,可帮忙开发人员构建高度可扩大的数据密集型实时应用程序(RTA)。您能够应用 Nodejs 构建前端和后端应用程序。 Node.js 通常用于构建以下应用程序 Chat applications(聊天利用)Streaming applications(流利用)Browser games(浏览器游戏)Command-line tools(命令行工具)Embedded systems(嵌入式零碎)在他们的技术栈中应用 NodeJS 的顶级公司包含 PayPal、Netflix 和 Uber 等。 装置 Node.JS 的办法次要有三种: 从 NodeSource 存储库装置 Node.JS从发行版的官网存储库装置 Node.JS应用 NVM 装置 Node.JS让咱们来看看如何应用这些办法在 RHEL 9 上装置 Node.JS。 先决条件Minimal Installed RHEL 9 SystemSudo User with admin rightsInternet ConnectivityRed Hat Subscription or locally configured repository从 NodeSource 库装置 Node.jsNodeSource 是一家技术公司,旨在帮忙组织运行生产的 node.js 应用程序,更多地关注资源应用和加强安全性以及应用程序性能。它提供了最新版本的 node.js 和 npm。 要从 Nodesource 装置 Node.sj,请首先更新零碎软件包,如图所示。 ...

November 28, 2022 · 2 min · jiezi

关于node.js:nodejs递归文件夹获取所有文件路径

读取文件夹fs.readdirSync('./')判断文件类型fs.statSync(item).isDirectory()门路拼接path.resolve(dir, item)封装function deepGetFile(dir) { let backList = [] let list = fs.readdirSync(dir) for (let index in list) { let item = path.resolve(dir, list[index]) if (fs.statSync(item).isDirectory()) { backList = backList.concat(deepGetFile(item)) } else { backList.push(item) } } return backList}

November 27, 2022 · 1 min · jiezi

关于node.js:深度理解NodeJS事件循环

导读ALL THE TIME,咱们写的的大部分javascript代码都是在浏览器环境下编译运行的,因而可能咱们对浏览器的事件循环机制理解比Node.JS的事件循环更深刻一些,然而最近写开始深刻NodeJS学习的时候,发现NodeJS的事件循环机制和浏览器端有很大的区别,特此记录来深刻的学习了下,以帮忙本人及小伙伴们遗记后查阅及了解。 什么是事件循环首先咱们须要理解一下最根底的一些货色,比方这个事件循环,事件循环是指Node.js执行非阻塞I/O操作,只管==JavaScript是单线程的==,但因为大多数==内核都是多线程==的,Node.js会尽可能将操作装载到零碎内核。因而它们能够解决在后盾执行的多个操作。当其中一个操作实现时,内核会通知Node.js,以便Node.js能够将相应的回调增加到轮询队列中以最终执行。 当Node.js启动时会初始化event loop, 每一个event loop都会蕴含按如下程序六个循环阶段: ┌───────────────────────┐┌─>│ timers ││ └──────────┬────────────┘│ ┌──────────┴────────────┐│ │ I/O callbacks ││ └──────────┬────────────┘│ ┌──────────┴────────────┐│ │ idle, prepare ││ └──────────┬────────────┘ ┌───────────────┐│ ┌──────────┴────────────┐ │ incoming: ││ │ poll │<─────┤ connections, ││ └──────────┬────────────┘ │ data, etc. ││ ┌──────────┴────────────┐ └───────────────┘│ │ check ││ └──────────┬────────────┘│ ┌──────────┴────────────┐└──┤ close callbacks │ └───────────────────────┘[x] 1. timers 阶段: 这个阶段执行 setTimeout(callback) 和 setInterval(callback) 预约的 callback;[x] 2. I/O callbacks 阶段: 此阶段执行某些零碎操作的回调,例如TCP谬误的类型。 例如,如果TCP套接字在尝试连贯时收到 ECONNREFUSED,则某些* nix零碎心愿期待报告谬误。 这将操作将期待在==I/O回调阶段==执行;[x] 3. idle, prepare 阶段: 仅node外部应用;[x] 4. poll 阶段: 获取新的I/O事件, 例如操作读取文件等等,适当的条件下node将阻塞在这里;[x] 5. check 阶段: 执行 setImmediate() 设定的callbacks;[x] 6. close callbacks 阶段: 比方 socket.on(‘close’, callback) 的callback会在这个阶段执行;事件循环详解 ...

November 18, 2022 · 4 min · jiezi

关于node.js:深度阐述Nodejs模块机制

咱们都晓得Nodejs遵循的是CommonJS标准,当咱们require('moduleA')时,模块是怎么通过名字或者门路获取到模块的呢?首先要聊一下模块援用、模块定义、模块标识三个概念。 1 CommonJS标准1.1 模块援用模块上下文提供require()办法来引入内部模块,看似简略的require函数, 其实外部做了大量工作。示例代码如下: //test.js//引入一个模块到以后上下文中const math = require('math');math.add(1, 2);1.2 模块定义模块上下文提供了exports对象用于导入导出以后模块的办法或者变量,并且它是惟一的导出进口。模块中存在一个module对象,它代表模块本身,exports是module的属性。一个文件就是一个模块,将办法作为属性挂载在exports上就能够定义导出的形式: //math.jsexports.add = function () { let sum = 0, i = 0, args = arguments, l = args.length; while(i < l) { sum += args[i++]; } return sum;}这样就可像test.js里那样在require()之后调用模块的属性或者办法了。 1.3 模块标识模块标识就是传递给require()办法的参数,它必须是合乎小驼峰命名的字符串,或者以.、..结尾的相对路径或者绝对路径,能够没有文件后缀名.js. 2. Node的模块实现在Node中引入模块,须要经验如下四个步骤: 路径分析文件定位编译执行退出内存2.1 路径分析Node.js中模块能够通过文件门路或名字获取模块的援用。模块的援用会映射到一个js文件门路。 在Node中模块分为两类: 一是Node提供的模块,称为外围模块(内置模块),内置模块公开了一些罕用的API给开发者,并且它们在Node过程开始的时候就预加载了。另一类是用户编写的模块,称为文件模块。如通过NPM装置的第三方模块(third-party modules)或本地模块(local modules),每个模块都会裸露一个公开的API。以便开发者能够导入。如const mod = require('module_name')const { methodA } = require('module_name')执行后,Node外部会载入内置模块或通过NPM装置的模块。require函数会返回一个对象,该对象公开的API可能是函数、对象或者属性如函数、数组甚至任意类型的JS对象。 外围模块是Node源码在编译过程中编译进了二进制执行文件。在Node启动时这些模块就被加载进内存中,所以外围模块引入时省去了文件定位和编译执行两个步骤,并且在路径分析中优先判断,因而外围模块的加载速度是最快的。文件模块则是在运行时动静加载,速度比外围模块慢。 这里列下node模块的载入及缓存机制: 1、载入内置模块(A Core Module) 2、载入文件模块(A File Module) 3、载入文件目录模块(A Folder Module) 4、载入node_modules里的模块 ...

November 18, 2022 · 3 min · jiezi

关于node.js:深聊Nodejs模块化

本文只探讨 CommonJS 标准,不波及 ESM咱们晓得 JavaScript 这门语言诞生之初次要是为了实现网页上表单的一些规定校验以及动画制作,所以布兰登.艾奇(Brendan Eich)只花了一周多就把 JavaScript 设计进去了。能够说 JavaScript 从出世开始就带着许多缺点和毛病,这一点始终被其余语言的编程者所讥笑。随着 BS 开发模式慢慢地火了起来,JavaScript 所要承当的责任也越来越大,ECMA 接手标准化之后也慢慢的开始欠缺了起来。 在 ES 6 之前,JavaScript 始终是没有本人的模块化机制的,JavaScript 文件之间无奈互相援用,只能依赖脚本的加载程序以及全局变量来确定变量的传递程序和传递形式。而 script 标签太多会导致文件之间依赖关系凌乱,全局变量太多也会导致数据流相当错乱,命名抵触和内存透露也会更加频繁的呈现。直到 ES 6 之后,JavaScript 开始有了本人的模块化机制,不必再依赖 requirejs、seajs 等插件来实现模块化了。 在 Nodejs 呈现之前,服务端 JavaScript 基本上处于一片荒凉的境况,而过后也没有呈现 ES 6 的模块化标准(Nodejs 最早从 V8.5 开始反对 ESM 标准:Node V8.5 更新日志),所以 Nodejs 采纳了过后比拟先进的一种模块化标准来实现服务端 JavaScript 的模块化机制,它就是 CommonJS,有时也简称为 CJS。 这篇文章次要解说 CommonJS 在 Nodejs 中的实现。 一、CommonJS 标准在 Nodejs 采纳 CommonJS 标准之前,还存在以下毛病: 没有模块零碎规范库很少没有标准接口不足包管理系统这几点问题的存在导致 Nodejs 始终难以构建大型的我的项目,生态环境也是非常的贫乏,所以这些问题都是亟待解决的。 CommonJS 的提出,次要是为了补救以后 JavaScript 没有模块化规范的缺点,以达到像 Java、Python、Ruby 那样可能构建大型利用的阶段,而不是仅仅作为一门脚本语言。Nodejs 可能领有明天这样凋敝的生态系统,CommonJS 功不可没。 ...

November 18, 2022 · 8 min · jiezi

关于node.js:深入nodejs的eventloop

此处如无非凡指出的话,event loop的语境都是指nodejs 本文研究所用的nodejs环境是:操作系统window10 + nodejs版本号为v12.16.2 什么是event loop?event loop是指由libuv提供的,一种实现非阻塞I/O的机制。具体来讲,因为javascript一门single-threaded编程语言,所以nodejs只能把异步I/O操作的实现(非阻塞I/O的实现后果的就是异步I/O)转交给libuv来做。因为I/O既可能产生在很多不同操作系统上(Unix,Linux,Mac OX,Window),又能够分为很多不同类型的I/O(file I/O, Network I/O, DNS I/O,database I/O等)。所以,对于libuv而言,如果以后系统对某种类型的I/O操作提供相应的异步接口的话,那么libuv就应用这些现成的接口,否则的话就启动一个线程池来本人实现。这就是官网文档所说的:“事件循环使Node.js能够通过将操作转移到零碎内核中来执行非阻塞I / O操作(只管JavaScript是单线程的)”的意思。 The event loop is what allows Node.js to perform non-blocking I/O operations — despite the fact that JavaScript is single-threaded — by offloading operations to the system kernel whenever possible.nodejs的架构在持续探讨nodejs event loop之前,咱们无妨来看看nodejs的架构图: 从下面的架构图,你能够看出,libuv是位于架构的最底层的。而咱们所要讲得event loop的实现是由libuv来提供的。当初,你的脑海外面应该有一幅残缺的画面,并分明地晓得event loop到底处在哪个地位了。 这里值得强调的一点是,无论是chrome浏览器中的还是nodejs中的event loop,其实都不是由v8引擎来实现的。 对于event loop几个误会误会1:event loop和用户代码别离跑在不同的线程上常常听到这样的说法,用户的javascript代码跑在主线程上,nodejs其余的javascript代码(不是用户写的)跑在event loop的这个线程上。每一次当有异步操作产生的时候,主线程会把I/O操作的实现交给event loop线程。当异步I/O有了后果之后,event loop线程就会把后果告诉主线程,主线程就会去执行用户注册的callback函数。 假相不论是用户写的还是nodejs自身内置的javascript代码(nodejs API),所有的javascript代码都运行在同一个线程外面。在nodejs的角度看来,所有的javascript代码要么是同步代码,要么就是异步代码。或者咱们能够这样说,所有的同步代码的执行都是由v8来实现的,所有异步代码的执行都是由libuv提供的event loop功能模块来实现的。那event loop与v8是什么关系呢?咱们能够看看上面的源代码: Environment* CreateEnvironment(Isolate* isolate, uv_loop_t* loop, Handle<Context> context, int argc, const char* const* argv, int exec_argc, const char* const* exec_argv) { HandleScope handle_scope(isolate); Context::Scope context_scope(context); Environment* env = Environment::New(context, loop); isolate->SetAutorunMicrotasks(false); uv_check_init(env->event_loop(), env->immediate_check_handle()); uv_unref(reinterpret_cast<uv_handle_t*>(env->immediate_check_handle())); uv_idle_init(env->event_loop(), env->immediate_idle_handle()); uv_prepare_init(env->event_loop(), env->idle_prepare_handle()); uv_check_init(env->event_loop(), env->idle_check_handle()); uv_unref(reinterpret_cast<uv_handle_t*>(env->idle_prepare_handle())); uv_unref(reinterpret_cast<uv_handle_t*>(env->idle_check_handle())); // Register handle cleanups env->RegisterHandleCleanup(reinterpret_cast<uv_handle_t*>(env->immediate_check_handle()), HandleCleanup, nullptr); env->RegisterHandleCleanup(reinterpret_cast<uv_handle_t*>(env->immediate_idle_handle()), HandleCleanup, nullptr); env->RegisterHandleCleanup(reinterpret_cast<uv_handle_t*>(env->idle_prepare_handle()), HandleCleanup, nullptr); env->RegisterHandleCleanup(reinterpret_cast<uv_handle_t*>(env->idle_check_handle()), HandleCleanup, nullptr); if (v8_is_profiling) { StartProfilerIdleNotifier(env); } Local<FunctionTemplate> process_template = FunctionTemplate::New(isolate); process_template->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "process")); Local<Object> process_object = process_template->GetFunction()->NewInstance(); env->set_process_object(process_object); SetupProcessObject(env, argc, argv, exec_argc, exec_argv); LoadAsyncWrapperInfo(env); return env;}能够看到,nodejs在创立v8环境的时候,会把libuv默认的event loop作为参数传递进去的。event loop是被v8所应用一个功能模块。因而,咱们能够说,v8蕴含了event loop。 ...

November 16, 2022 · 3 min · jiezi

关于node.js:深入剖析nodejs中间件

nodejs的呈现为前端行业带来了有限的可能性,让很多原来只负责客户端开发的同学也缓缓开始接触和应用服务器端技术. 尽管nodejs带来了很多的益处,然而它也存在本身的局限性.和那些传统老牌的编程语言相比,如JAVA,PHP.nodejs并不能成为它们的替代品,而且在可预估的将来,也很难撼动那些老牌编程语言的位置. 目前nodejs次要有以下几个利用场景. 前端工程化,比方rollup,webpack在工程化方向的摸索nodejs中间层客户端集成nodejs,比方electron市面上一些不太简单的利用抉择nodejs作为后端编程语言本文次要讲一讲nodejs作为中间层的一些实际,查看下图. 传统的的开发模式由浏览器间接和Server层间接通信,中间层的退出意味着在浏览器和Server层之间额定增加了一层. 原来客户端间接向Server发送申请,Server层收到申请后通过计算解决将后果返回给浏览器. 现在浏览器将申请发送给node层,node层通过一轮解决后再向Server层发动申请.Server层处理完毕将响应后果返回给node层,node层最初将数据返回给浏览器. 因为node层的呈现,Server层能够只用关注业务自身,而不用理睬前端对字段的特殊要求。 node层能够向server层获取数据,再通过对数据的计算整合转换成合乎前端UI要求的数据格式.另外整个利用如果采纳微服务架构,那么Server层会有很多台治理独自业务模块的服务器,node层就很好的适配了微服务的架构,它能够向多台服务器发动申请获取到不同模块的数据再整合转化发送给前端. 上面着重介绍一下nodejs作为中间层的局部实际. 代理转发代理转发在理论中有很多宽泛的利用.浏览器首先将申请发送给node服务器,申请收到后node服务器能够对申请做一些解决,比方将原来的门路变换一下,申请头的信息扭转一下,再把批改后的申请发送给近程实在的服务器. 近程服务器计算出响应后果再返回给node服务器,node服务器依然能够对响应做选择性解决再分返回给浏览器. 代理转发能够解决前端日常开发中常常遇到的跨域问题,另外它还屏蔽了近程实在服务器的细节,让浏览器只与node服务器通信.上面是简略的实际. const express = require('express');const { createProxyMiddleware } = require('http-proxy-middleware');const app = express();//创立利用app.use("/api",createProxyMiddleware( //设置代理转发 { target: 'http://www.xxx.com', //举例轻易写的地址 changeOrigin: true, pathRewrite: function (path) { return path.replace('/api', '/server/api'); } }));app.use("*",(req,res)=>{ //不是以'/api'结尾的路由全副返回"hello world" res.send("hello world");})app.listen(3000);http-proxy-middleware是一个第三方依赖包,能够十分不便设置代理转发,须要通过npm装置. 如果以后拜访的门路是以/api结尾,那么该申请就会被http-proxy-middleware拦挡.察看http-proxy-middleware外面配置的参数. target代表近程实在服务器的地址.changeOrigin设置为true,示意将申请转发到target地址上.pathRewrite是对申请门路做一下解决,将/api转换成/server/api.下面的案例意思很显著,如果以后浏览器拜访http://localhost:3000/api/list.因为这个门路以/api结尾所以会被拦挡,从而触发pathRewrite函数批改拜访门路.最终拜访门路就变成了http://www.xxx.com/server/api/list,而后就会向这个门路发动申请,失去响应后再返回给浏览器, 接口聚合下面介绍的接口转发在实践中很少会独自利用,如果仅仅只是为了转发一下数据,那还不如间接用nginx配置一下,转发就搞定了. 如果接口聚合和接口转发都须要,那么从代码层面去解决还是优先思考的形式. 接口聚合是什么意思呢?假如当初企业有两个销售体系,一个是线上的电商平台销售,另一个是线下实体店.它们别离属于不同的团队经营,保护着不同的数据系统. 如果以后申请只是想查问一下电商平台某款商品的信息,只须要将接口转发给电商平台零碎即可.同理如果仅仅只是查问线下实体店某一天的销售业绩,能够间接把申请转发给线下数据系统查问,再把响应数据返回.下面介绍的插件http-proxy-middleware反对配置多个代理门路,具体可查问文档. 当初有这么一个需要,指标是查问本周某款商品在线上和线下销售数据的比照.那么这个时候就须要node层向两个近程服务器发送申请别离获取线上销售数据和线下销售数据,将这两局部数据聚合解决后再返回给前端.简略实际如下. const express = require('express');const { createProxyMiddleware } = require('http-proxy-middleware');const app = express();//创立利用//伪代码app.get("/getSaleInfo",async (req,res)=>{ const online_data = await getOnline(); //获取线上数据 const offline_data = await getOffline(); //获取线下数据 res.send(dataHanlder(online_data,offline_data)); //对数据处理后返回给前端})proxyHanlder(app);//伪代码,将代理转发的逻辑封装起来app.use("*",(req,res)=>{ res.send("hello world");})app.listen(3000);/getSaleInfo代表着将两条数据聚合的自定义路由,如果须要聚合数据的需要比拟多,这块逻辑要独自封装到路由模块中治理,并且要写在代理转发的后面. ...

November 16, 2022 · 1 min · jiezi

关于node.js:深入理解Nodejs的进程与子进程

过程:process模块process 模块是 nodejs 提供给开发者用来和以后过程交互的工具,它的提供了很多实用的 API。从文档登程,管中窥豹,进一步意识和学习 process 模块: 如何解决命令参数?如何解决工作目录?如何解决异样?如何解决过程退出?process 的规范流对象深刻了解 process.nextTick如何解决命令参数?命令行参数指的是 2 个方面: 传给 node 的参数。例如 node --harmony script.js --version 中,--harmony 就是传给 node 的参数传给过程的参数。例如 node script.js --version --help 中,--version --help 就是传给过程的参数它们别离通过 process.argv 和 process.execArgv 来取得。 如何解决工作目录?通过process.cwd()能够获取以后的工作目录。 通过process.chdir(directory)能够切换以后的工作目录,失败后会抛出异样。实际如下: function safeChdir(dir) { try { process.chdir(dir); return true; } catch (error) { return false; }}如何解决异样?uncaughtException 事件Nodejs 能够通过 try-catch 来捕捉异样。如果异样未捕捉,则会始终从底向事件循环冒泡。如是冒泡到事件循环的异样没被解决,那么就会导致以后过程异样退出。 依据文档,能够通过监听 process 的 uncaughtException 事件,来解决未捕捉的异样: process.on("uncaughtException", (err, origin) => { console.log(err.message);});const a = 1 / b;console.log("abc"); // 不会执行下面的代码,控制台的输入是:b is not defined。捕捉了错误信息,并且过程以0退出。开发者能够在 uncaughtException 事件中,革除一些曾经调配的资源(文件描述符、句柄等),不举荐在其中重启过程。 ...

November 16, 2022 · 3 min · jiezi

关于node.js:windows下设置processenvUVTHREADPOOLSIZE无效

node在执行IO操作(读取文件)时会开启线程池(默认是4个),咱们能够通过设置UV_THREADPOOL_SIZE减少线程池个数。 背景: <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title></head><body> </body></html>const fs = require("fs");process.env.UV_THREADPOOL_SIZE=64;setInterval(() => { fs.readFile(`${__dirname}/index.html`,()=>{ console.log("read success"); })}, 3000);{ "name": "threadpool", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start":"node index.js" }, "keywords": [], "author": "", "license": "ISC"}在windows下运行node,发现process.env.UV_THREADPOOL_SIZE设置有效。 线程数量应该从12减少到76个,理论为16个,阐明UV_THREADPOOL_SIZE设置有效 起因:Linux零碎下能够在js代码里间接设置,而windows零碎下须要在执行node命令前设置线程池数量,将node启动改为如下图(注:=号左右不要有空格)运行后果:

November 8, 2022 · 1 min · jiezi

关于node.js:ubuntu-上的-yarn-安装的可执行文件在哪里

ubuntu 上的 yarn 装置的可执行文件在哪里? 应用 yarn 装置一些货色 (svddb_service) ╭─[email protected] ~/code/vobile/svddb_service ‹master*› ╰─➤ yarn global add vcicd-cli yarn global v1.22.19[1/4] Resolving packages...[2/4] Fetching packages...[3/4] Linking dependencies...[4/4] Building fresh packages...success Installed "[email protected]" with binaries: - cicdDone in 9.49s.然而要用的时候,却没有 ╰─➤ cicd zsh: command not found: cicd怎么办? 通过 yarn全局装置后命令为何不能应用? 理解到,用上面的形式就能够查看了: ╰─➤ yarn global bin /home/pon/.yarn/bin

November 7, 2022 · 1 min · jiezi

关于node.js:理解Nodejs中的进程间通信

前置常识文件描述符在 Linux 零碎中,所有都看成文件,当过程关上现有文件时,会返回一个文件描述符。文件描述符是操作系统为了治理曾经被过程关上的文件所创立的索引,用来指向被关上的文件。当咱们的过程启动之后,操作系统会给每一个过程调配一个 PCB 管制块,PCB 中会有一个文件描述符表,寄存以后过程所有的文件描述符,即以后过程关上的所有文件。 过程中的文件描述符是如何和系统文件对应起来的?在内核中,零碎会保护另外两种表 关上文件表(Open file table)i-node 表(i-node table)文件描述符就是数组的下标,从0开始往上递增,0/1/2 默认是咱们的输出/输入/谬误流的文件描述符在 PCB 中保护的文件形容表中,能够依据文件描述符找到对应了文件指针,找到对应的关上文件表关上文件表中保护了:文件偏移量(读写文件的时候会更新);对于文件的状态标识;指向 i-node 表的指针想要真正的操作文件,还得靠 i-node 表,可能获取到实在文件的相干信息 他们之间的关系 图解 在过程 A 中,文件描述符1/20均指向了同一关上文件表项23,这可能是对同一文件屡次调用了 open 函数造成的过程 A/B 的文件描述符2都指向同一文件,这可能是调用了 fork 创立子过程,A/B 是父子关系过程过程 A 的文件描述符0和过程 B 的文件描述符指向了不同的关上文件表项,但这些表项指向了同一个文件,这可能是 A/B 过程别离对同一文件发动了 open 调用总结 同一过程的不同文件描述符能够指向同一个文件不同过程能够领有雷同的文件描述符不同过程的同一文件描述符能够指向不同的文件不同过程的不同文件描述符能够指向同一个文件文件描述符的重定向每次读写过程的时候,都是从文件描述符下手,找到对应的关上文件表项,再找到对应的 i-node 表 如何实现文件描述符重定向?因为在文件描述符表中,可能找到对应的文件指针,如果咱们扭转了文件指针,是不是后续的两个表内容就产生了扭转例如:文件描述符1指向的显示器,那么将文件描述符1指向 log.txt 文件,那么文件描述符 1 也就和 log.txt 对应起来了 shell 对文件描述符的重定向是输入重定向符号,< 是输出重定向符号,它们是文件描述符操作符和 < 通过批改文件描述符扭转了文件指针的指向,来可能实现重定向的性能咱们应用cat hello.txt时,默认会将后果输入到显示器上,应用 > 来重定向。cat hello.txt 1 > log.txt 以输入的形式关上文件 log.txt,并绑定到文件描述符1上 c函数对文件描述符的重定向dupdup 函数是用来关上一个新的文件描述符,指向和 oldfd 同一个文件,共享文件偏移量和文件状态, ...

November 7, 2022 · 5 min · jiezi

关于node.js:用-nodejs-搭建脚手架

1 前言1.1像咱们相熟的 vue-cli,taro-cli 等脚手架,只须要输出简略的命令 taro init project,即可疾速帮咱们生成一个初始我的项目。在日常开发中,有一个脚手架工具能够用来进步工作效率。 1.2 为什么须要脚手架缩小重复性的工作,从零创立一个我的项目和文件。依据交互动静生成我的项目构造和配置文件等。多人合作更为不便,不须要把文件传来传去。1.3 怎么来搭建呢?脚手架是怎么样进行构建的呢,我是借助了taro-cli 的思路。 1.4 本文的指标读者1 想要学习更多和理解更多的人2 对技术充满热情2 搭建前筹备2.1 第三方工具commander.js,能够主动的解析命令和参数,用于解决用户输出的命令。download-git-repo,下载并提取 git 仓库,用于下载我的项目模板。Inquirer.js,通用的命令行用户界面汇合,用于和用户进行交互。handlebars.js,模板引擎,将用户提交的信息动静填充到文件中。ora,下载过程久的话,能够用于显示下载中的动画成果。chalk,能够给终端的字体加上色彩。og-symbols,能够在终端上显示出 √ 或 × 等的图标2.2 上手2.2.1 新建一个文件夹,而后npm init初始化npm 不单单用来治理你的利用和网页的依赖,你还能用它来封装和散发新的 shell 命令。 $ mkdir lq-cli$ npm init 这时在咱们的 lq-cli 我的项目中有 package.json 文件,而后须要创立一个 JS 文件蕴含咱们的脚本就取名 index.js 吧。package.json 内容如下 { "name": "lq-shell", "version": "1.0.0", "description": "脚手架搭建", "main": "index.js", "bin": { "lq": "./index.js" }, "scripts": { "test": "test" }, "keywords": [ "cli" ], "author": "prune", "license": "ISC"}index.js内容如下 ...

November 7, 2022 · 2 min · jiezi

关于node.js:细说nodejs的path模块

前言path 模块是 nodejs 中用于解决文件/目录门路的一个内置模块,能够看作是一个工具箱,提供诸多办法供咱们应用,当然都是和门路解决无关的。同时在前端开发中 path 模块呈现的频率也是比拟高的,比方配置 webpack 的时候等。本文是对该模块中一些罕用的办法进行介绍,走,一起学习下吧。 须要留神下,nodejs 中所有的模块(内置,自定义)都须要应用 requier 进行导入,个别导入地位在文件顶部。const path = require('path');APIbasename (获取门路根底名)path.basename(path[,ext]) path:文件/目录门路ext:(可选)文件扩展名 例如 .js .css 等返回值:path 门路的最初一部分留神: 如果 path 不是字符串或者给定的 ext 参数不是字符串,则抛出 TypeError如果有 ext 参数,当 ext 后缀名与文件名匹配上时返回的文件名会省略文件后缀如果 path 尾部有目录分隔符则会被疏忽const path = require("path");path.basename('./ext/test.js') //test.jspath.basename('./ext/test.js','.js') //test (当后缀名与文件名匹配上时返回的文件名会省略文件后缀)path.basename('./ext/test.js','.html') //test.js (没有匹配上时返回文件全名)path.basename('./ext/foo/') // foo (尾部目录分隔符被疏忽)dirname (获取门路目录名)path.dirname(path) path:文件/目录门路返回值:path 门路的目录名留神: 如果 path 不是字符串,则抛出 TypeError如果 path 尾部有目录分隔符则会被疏忽const path = require("path");path.dirname('./foo/bar/baz'); //./foo/bar (相对路径/绝对路径均可)path.dirname('/foo/bar/baz/'); // /foo/bar (尾部目录分隔符被疏忽)path.dirname('/foo/bar/baz/test.js'); // /foo/bar/bazextname (获取门路扩展名)path.extname(path) path:文件/目录门路返回值:path 门路的扩展名,从最初一次呈现 '.' 字符到 path 最初一部分的字符串完结,无扩展名则返回空留神: ...

November 7, 2022 · 3 min · jiezi

关于node.js:使用nodejs修改项目packagejson版本号

背景:本人的我的项目在部署上传之前须要更新版本号能力胜利部署代码具体代码如下(nodejs简陋); 正文了主动创立分支+提交动作;可依据需要自行应用 //build.js文件var exec = require('child_process').exec // 异步子过程var fs = require('fs')var packageJSON = require('./package.json')/** package.json文件的version参数 */var version = packageJSON.version/** 命令行的所有参数 */var options = process.argv/** 命令行的type参数 */var type = null/** 新的version参数 */var newVersion = null//判断命令行是否存在type参数或version参数进行逻辑解决for (let i = 0; i < options.length; i++) { if (options[i].indexOf('type') > -1) { //存在type参数 type = options[i].split('=')[1] } else if (options[i].indexOf('version') > -1) { //存在version参数 newVersion = options[i].split('=')[1] } else { //code }}if (newVersion) { //存在设置version参数则扭转原来的version version = newVersion} else if (type) { //不设置version则依据type来进行批改version version = handleType(version, type)} else { version = null console.log('-----------没有扭转version-----------')}//批改了version则写入if (version) { packageJSON.version = version //同步写入package.json文件 fs.writeFileSync('package.json', JSON.stringify(packageJSON, null, 2)) console.log('-----------更新package的version为:%s参数胜利-----------', version) // handleGitAdd('./package.json') // pullRemote()}/** * 依据分支类型解决版本号version * @param {string} oldVersion 旧的版本号 * @param {string} type 分支类型 * @private */function handleType(oldVersion, type) { var oldVersionArr = oldVersion.split('.') //版本号第一位 如:1.2.3 则为 1 var firstNum = +oldVersionArr[0] //版本号第二位 如:1.2.3 则为 2 var secondNum = +oldVersionArr[1] //版本号第三位 如:1.2.3 则为 3 var thirdNum = +oldVersionArr[2] switch (type) { case 'release': //release分支的解决逻辑 ++secondNum thirdNum = 0 break case 'hotfix': //hotfix分支的解决逻辑 ++thirdNum break default: // 默认依照最小版本解决 ++thirdNum break } return firstNum + '.' + secondNum + '.' + thirdNum}// /**// * 将package.json推送到近程新创建的分支// */// function pullRemote() {// var branch = type + '/' + version// //创立新分支// handleGitCreate(branch)// }// /**// * 创立新分支// * @param {string} branch 分支名// */// function handleGitCreate(branch) {// exec('git branch ' + branch, function (error, stdout, stderr) {// console.log('-----------创立新分支:%s DONE-----------', branch)// //切换分支// handleGitCheckOut(branch)// })// }// /**// * 切换分支// * @param {string} branch 分支名// */// function handleGitCheckOut(branch) {// exec('git checkout ' + branch, function (error, stdout, stderr) {// console.log('-----------切换新分支:%s DONE-----------', branch)// //增加批改文件// handleGitAdd('./package.json')// })// }/** * 增加批改文件 * @param {string} filePath 文件门路 */function handleGitAdd(filePath) { exec('git add ' + filePath, function (error, stdout, stderr) { console.log('[增加批改文件输入:%s]', stdout) //提交文件 handleGitCommit('更新package.json文件') })}/** * 提交文件 * @param {string} prompt commit文字备注 */function handleGitCommit(prompt) { // var branch = type + '/' + version exec('git commit -m "' + prompt + '"', function (error, stdout, stderr) { console.log('[提交批改文件输入:%s]', stdout) //推送分支 handleGitPush() })}/** * 推送分支 */function handleGitPush() { exec('git push ', function (error, stdout, stderr) { console.log('[推送至分支:%s输入:%s]', stdout || error || stderr) console.log('-----------提交批改文件实现-----------') })}/** * 主动生成版本号脚本思路 * 1.获取传进来的参数 √ * 2.依据参数进行逻辑解决 √ * 3.获取package.json中的version参数 √ * 4.批改version的值写入package.json文件 √ * 5.git提交package.json文件 √ */应用node build.js --type=hotfix 只批改最小版本node build.js --type=release 批改性能版本node build.js --type=release --version=0.0.8 批改为指定版本

November 4, 2022 · 2 min · jiezi

关于node.js:深聊Nodejs模块化

本文只探讨 CommonJS 标准,不波及 ESM咱们晓得 JavaScript 这门语言诞生之初次要是为了实现网页上表单的一些规定校验以及动画制作,所以布兰登.艾奇(Brendan Eich)只花了一周多就把 JavaScript 设计进去了。能够说 JavaScript 从出世开始就带着许多缺点和毛病,这一点始终被其余语言的编程者所讥笑。随着 BS 开发模式慢慢地火了起来,JavaScript 所要承当的责任也越来越大,ECMA 接手标准化之后也慢慢的开始欠缺了起来。 在 ES 6 之前,JavaScript 始终是没有本人的模块化机制的,JavaScript 文件之间无奈互相援用,只能依赖脚本的加载程序以及全局变量来确定变量的传递程序和传递形式。而 script 标签太多会导致文件之间依赖关系凌乱,全局变量太多也会导致数据流相当错乱,命名抵触和内存透露也会更加频繁的呈现。直到 ES 6 之后,JavaScript 开始有了本人的模块化机制,不必再依赖 requirejs、seajs 等插件来实现模块化了。 在 Nodejs 呈现之前,服务端 JavaScript 基本上处于一片荒凉的境况,而过后也没有呈现 ES 6 的模块化标准(Nodejs 最早从 V8.5 开始反对 ESM 标准:Node V8.5 更新日志),所以 Nodejs 采纳了过后比拟先进的一种模块化标准来实现服务端 JavaScript 的模块化机制,它就是 CommonJS,有时也简称为 CJS。 这篇文章次要解说 CommonJS 在 Nodejs 中的实现。 一、CommonJS 标准在 Nodejs 采纳 CommonJS 标准之前,还存在以下毛病: 没有模块零碎规范库很少没有标准接口不足包管理系统这几点问题的存在导致 Nodejs 始终难以构建大型的我的项目,生态环境也是非常的贫乏,所以这些问题都是亟待解决的。 CommonJS 的提出,次要是为了补救以后 JavaScript 没有模块化规范的缺点,以达到像 Java、Python、Ruby 那样可能构建大型利用的阶段,而不是仅仅作为一门脚本语言。Nodejs 可能领有明天这样凋敝的生态系统,CommonJS 功不可没。 ...

November 2, 2022 · 8 min · jiezi

关于node.js:理解NodeJS多进程

序言一次面试中,我提到本人用过pm2,面试接着问:「那你晓得pm2父子过程通信形式吗」。我大略据说pm2有cluster模式,但不分明父子过程如何通信。面试完结后把NodeJS的多过程重新整理了一下。 对于前端开发同学,肯定很分明js是单线程非阻塞的,这决定了NodeJS可能反对高性能的服务的开发。 JavaScript的单线程非阻塞个性让NodeJS适宜IO密集型利用,因为JavaScript在拜访磁盘/数据库/RPC等时候不须要阻塞期待后果,而是能够异步监听后果,同时持续向下执行。 但js不适宜计算密集型利用,因为当JavaScript遇到消耗计算性能的工作时候,单线程的毛病就裸露进去了。前面的工作都要被阻塞,直到耗时工作执行结束。 为了优化NodeJS不适宜计算密集型工作的问题,NodeJS提供了多线程和多过程的反对。 多过程和多线程从两个方面对计算密集型工作进行了优化,异步和并发: 异步,对于耗时工作,能够新建一个线程或者过程来执行,执行结束再告诉主线程/过程。看上面例子,这是一个koa接口,外面有耗时工作,会阻塞其余工作执行。 const Koa = require('koa');const app = new Koa();app.use(async ctx => { const url = ctx.request.url; if (url === '/') { ctx.body = 'hello'; } if (url === '/compute') { let sum = 0; for (let i = 0; i < 1e20; i++) { sum += i; } ctx.body = `${sum}`; }});app.listen(3000, () => { console.log('http://localhost:300/ start')});能够通过多线程和多过程来解决这个问题。 NodeJS提供多线程模块worker_threads,其中Woker模块用来创立线程,parentPort用在子线程中,能够获取主线程援用,子线程通过parentPort.postMessage发送数据给主线程,主线程通过worker.on承受数据。 //api.jsconst Koa = require('koa');const app = new Koa();const {Worker} = require('worker_threads');app.use(async (ctx) => { const url = ctx.request.url; if (url === '/') { ctx.body = 'hello'; } if (url === '/compute') { const sum = await new Promise(resolve => { const worker = new Worker(__dirname + '/compute.js'); //接管信息 worker.on('message', data => { resolve(data); }) }); ctx.body = `${sum}`; }})app.listen(3000, () => { console.log('http://localhost:3000/ start')});//computer.jsconst {parentPort} = require('worker_threads')let sum = 0;for (let i = 0; i < 1e20; i++) { sum += i;}//发送信息parentPort.postMessage(sum);上面是应用多过程解决耗时工作的办法,多过程模块child_process提供了fork办法(前面会介绍更多创立子过程的办法),能够用来创立子过程,主过程通过fork返回值(worker)持有子过程的援用,并通过worker.on监听子过程发送的数据,子过程通过process.send给父过程发送数据。 ...

November 2, 2022 · 4 min · jiezi

关于node.js:深入剖析nodejs中间件

nodejs的呈现为前端行业带来了有限的可能性,让很多原来只负责客户端开发的同学也缓缓开始接触和应用服务器端技术. 尽管nodejs带来了很多的益处,然而它也存在本身的局限性.和那些传统老牌的编程语言相比,如JAVA,PHP.nodejs并不能成为它们的替代品,而且在可预估的将来,也很难撼动那些老牌编程语言的位置. 目前nodejs次要有以下几个利用场景. 前端工程化,比方rollup,webpack在工程化方向的摸索nodejs中间层客户端集成nodejs,比方electron市面上一些不太简单的利用抉择nodejs作为后端编程语言本文次要讲一讲nodejs作为中间层的一些实际,查看下图. 传统的的开发模式由浏览器间接和Server层间接通信,中间层的退出意味着在浏览器和Server层之间额定增加了一层. 原来客户端间接向Server发送申请,Server层收到申请后通过计算解决将后果返回给浏览器. 现在浏览器将申请发送给node层,node层通过一轮解决后再向Server层发动申请.Server层处理完毕将响应后果返回给node层,node层最初将数据返回给浏览器. 因为node层的呈现,Server层能够只用关注业务自身,而不用理睬前端对字段的特殊要求。 node层能够向server层获取数据,再通过对数据的计算整合转换成合乎前端UI要求的数据格式.另外整个利用如果采纳微服务架构,那么Server层会有很多台治理独自业务模块的服务器,node层就很好的适配了微服务的架构,它能够向多台服务器发动申请获取到不同模块的数据再整合转化发送给前端. 上面着重介绍一下nodejs作为中间层的局部实际. 代理转发代理转发在理论中有很多宽泛的利用.浏览器首先将申请发送给node服务器,申请收到后node服务器能够对申请做一些解决,比方将原来的门路变换一下,申请头的信息扭转一下,再把批改后的申请发送给近程实在的服务器. 近程服务器计算出响应后果再返回给node服务器,node服务器依然能够对响应做选择性解决再分返回给浏览器. 代理转发能够解决前端日常开发中常常遇到的跨域问题,另外它还屏蔽了近程实在服务器的细节,让浏览器只与node服务器通信.上面是简略的实际. const express = require('express');const { createProxyMiddleware } = require('http-proxy-middleware');const app = express();//创立利用app.use("/api",createProxyMiddleware( //设置代理转发 { target: 'http://www.xxx.com', //举例轻易写的地址 changeOrigin: true, pathRewrite: function (path) { return path.replace('/api', '/server/api'); } }));app.use("*",(req,res)=>{ //不是以'/api'结尾的路由全副返回"hello world" res.send("hello world");})app.listen(3000);http-proxy-middleware是一个第三方依赖包,能够十分不便设置代理转发,须要通过npm装置. 如果以后拜访的门路是以/api结尾,那么该申请就会被http-proxy-middleware拦挡.察看http-proxy-middleware外面配置的参数. target代表近程实在服务器的地址.changeOrigin设置为true,示意将申请转发到target地址上.pathRewrite是对申请门路做一下解决,将/api转换成/server/api.下面的案例意思很显著,如果以后浏览器拜访http://localhost:3000/api/list.因为这个门路以/api结尾所以会被拦挡,从而触发pathRewrite函数批改拜访门路.最终拜访门路就变成了http://www.xxx.com/server/api/list,而后就会向这个门路发动申请,失去响应后再返回给浏览器,参考nodejs进阶视频解说:进入学习 接口聚合下面介绍的接口转发在实践中很少会独自利用,如果仅仅只是为了转发一下数据,那还不如间接用nginx配置一下,转发就搞定了. 如果接口聚合和接口转发都须要,那么从代码层面去解决还是优先思考的形式. 接口聚合是什么意思呢?假如当初企业有两个销售体系,一个是线上的电商平台销售,另一个是线下实体店.它们别离属于不同的团队经营,保护着不同的数据系统. 如果以后申请只是想查问一下电商平台某款商品的信息,只须要将接口转发给电商平台零碎即可.同理如果仅仅只是查问线下实体店某一天的销售业绩,能够间接把申请转发给线下数据系统查问,再把响应数据返回.下面介绍的插件http-proxy-middleware反对配置多个代理门路,具体可查问文档. 当初有这么一个需要,指标是查问本周某款商品在线上和线下销售数据的比照.那么这个时候就须要node层向两个近程服务器发送申请别离获取线上销售数据和线下销售数据,将这两局部数据聚合解决后再返回给前端.简略实际如下. const express = require('express');const { createProxyMiddleware } = require('http-proxy-middleware');const app = express();//创立利用//伪代码app.get("/getSaleInfo",async (req,res)=>{ const online_data = await getOnline(); //获取线上数据 const offline_data = await getOffline(); //获取线下数据 res.send(dataHanlder(online_data,offline_data)); //对数据处理后返回给前端})proxyHanlder(app);//伪代码,将代理转发的逻辑封装起来app.use("*",(req,res)=>{ res.send("hello world");})app.listen(3000);/getSaleInfo代表着将两条数据聚合的自定义路由,如果须要聚合数据的需要比拟多,这块逻辑要独自封装到路由模块中治理,并且要写在代理转发的后面. ...

November 1, 2022 · 1 min · jiezi