关于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 1, 2022 · 3 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 1, 2022 · 4 min · jiezi

关于node.js:有用的内置Nodejs-APIs

前言在构建你的第一个Node.js应用程序时,理解node开箱即用的实用工具和API是很有帮忙的,能够帮忙解决常见的用例和开发需要。 有用的Node.js APIsProcess:检索无关环境变量、参数、CPU应用状况和报告的信息。OS:检索Node正在运行的操作系统和零碎相干信息。比方CPU、操作系统版本、主目录等等。Util:有用和常见办法的汇合。用于帮忙解码文本、类型检查和比照对象。URL:轻松创立和解析URL。File System API:与文件系统交互。用于创立、读取、更新以及删除文件、目录和权限。Events:用于触发和订阅Node.js中的事件。其工作原理与客户端事件监听器相似。Streams:用于在更小和更容易治理的块中解决大量数据,以防止内存问题。Worker Threads:用来拆散不同线程上的函数执行,以防止瓶颈。对于CPU密集型的JavaScript操作很有用。Child Processes:容许你运行子过程,你能够监控并在必要时终止子过程。Clusters:容许你跨核fork任何数量的雷同过程,以更无效地解决负载。Processprocess对象提供无关你的Node.js应用程序以及管制办法的信息。能够应用该对象获取诸如环境变量、CPU和内存应用状况等信息。process是全局可用的:你能够在不import的状况下应用它。只管Node.js文档举荐你显示地援用: import process from 'process';process.argv:返回一个数组。该数组的前两个元素是Node.js的可执行门路和脚本名称。索引为2的数组项是传递的第一个参数。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 }。将该对象传给该办法,以取得一个绝对的读数。process.memoryUsage():返回一个以字节为单位形容内存应用状况的对象。process.version:返回Node.js版本的字符串。比方18.0.0。process.report:生成诊断报告。process.exit(code):退出以后应用程序。应用退出码0来示意胜利,或在必要时应用适当的错误代码。OS[OS](https://nodejs.org/dist/latest/docs/api/os.html)API与process相似。但它也能够返回无关Node.js运行的操作系统的信息。它提供了诸如操作系统版本、CPU和启动工夫等信息。 os.cpus():返回一个蕴含每个逻辑CPU核信息的对象数组。Clusters局部援用os.cpus()来fork过程。在一个16核CPU中,你会有16个Node.js应用程序的实例在运行以进步性能。os.hostname():操作系统主机名。os.version():标识操作系统内核版本的字符串。os.homedir():用户主目录的残缺门路。os.tmpdir():操作系统默认长期文件目录的残缺门路。os.uptime():操作系统已运行的秒数。Utilutil模块提供了各种有用的JavaScript办法。其中最有用的是util.promisify(function),该办法接管谬误优先类型的回调函数,并返回基于promise的函数。Util模块还能够帮忙解决一些常见模式,诸如解码文本、类型检查和查看对象。 util.callbackify(function):接管一个返回promise的函数,并返回一个基于回调的函数。util.isDeepStrictEqual(object1, object2):当两个对象严格相等(所有子属性必须匹配)时返回true。util.format(format, [args]):返回一个应用类printf格局的字符串。util.inspect(object, options):返回一个对象的字符串示意,用于调试。与应用console.dir(object, { depth: null, color: true });相似。util.stripVTControlCharacters(str):剥离字符串中的ANSI本义代码。util.types:为罕用的JavaScript和Node.js值提供类型查看。比方: import util from 'util';util.types.isDate( new Date() ); // trueutil.types.isMap( new Map() ); // trueutil.types.isRegExp( /abc/ ); // trueutil.types.isAsyncFunction( async () => {} ); // trueURLURL是另一个全局对象,能够让你平安地创立、解析以及批改web URL。它对于从URL中疾速提取协定、端口、参数和哈希值十分有用,而不须要借助于正则。比方: { href: 'https://example.org:8000/path/?abc=123#target', origin: 'https://example.org:8000', protocol: 'https:', username: '', password: '', host: 'example.org:8000', hostname: 'example.org', port: '8000', pathname: '/path/', search: '?abc=123', searchParams: URLSearchParams { 'abc' => '123' }, hash: '#target'}你能够查看并更改任意属性。比方: ...

October 31, 2022 · 5 min · jiezi

关于node.js:一文读懂NodeJs知识体系和原理浅析

node.js 初探Node.js 是一个 JS 的服务端运行环境,简略的来说,它是在 JS 语言标准的根底上,封装了一些服务端的运行时对象,让咱们可能简略实现十分多的业务性能。 如果咱们只应用 JS 的话,实际上只是能进行一些简略的逻辑运算。node.js 就是基于 JS 语法减少与操作系统之间的交互。 node.js 的装置咱们能够应用多种形式来装置 node.js,node.js 实质上也是一种软件,咱们能够应用间接下载二进制安装文件装置,通过零碎包治理进行装置或者通过源码自行编译均可。 一般来讲,对于集体开发的电脑,咱们举荐间接通过 node.js 官网的二进制安装文件来装置。对于打包上线的一些 node.js 环境,也能够通过二进制编译的模式来装置。 装置胜利之后,咱们的 node 命令就会主动退出咱们的零碎环境变量 path 中,咱们就能间接在全局应用 node 命令拜访到咱们方才装置的 node 可执行命令行工具。 node.js 版本切换在个人电脑上,咱们能够装置一些工具,对 node.js 版本进行切换,例如 nvm 和 n。 nvm 的全称就是 node version manager,意思就是可能治理 node 版本的一个工具,它提供了一种间接通过 shell 执行的形式来进行装置。简略来说,就是通过将多个 node 版本装置在指定门路,而后通过 nvm 命令切换时,就会切换咱们环境变量中 node 命令指定的理论执行的软件门路。装置胜利之后,咱们就能在以后的操作系统中应用多个 node.js 版本。 包管理工具 npmcurl -o- https://raw.githubusercontent.com/nvm- sh/nvm/v0.35.3/install.sh | bash 咱们对 npm 应该都比拟相熟了,它是 node.js 内置的一款工具,目标在于装置和公布合乎 node.js 规范的模块,从而实现社区共建的目标凋敝整个社区。 ...

October 31, 2022 · 11 min · jiezi

关于node.js:彻底搞懂nodejs事件循环

nodejs是单线程执行的,同时它又是基于事件驱动的非阻塞IO编程模型。这就使得咱们不必期待异步操作后果返回,就能够持续往下执行代码。当异步事件触发之后,就会告诉主线程,主线程执行相应事件的回调。 以上是家喻户晓的内容。明天咱们从源码动手,剖析一下nodejs的事件循环机制。 nodejs架构首先,咱们先看下nodejs架构,下图所示: 如上图所示,nodejs自上而下分为 用户代码 ( js 代码 )用户代码即咱们编写的利用程序代码、npm包、nodejs内置的js模块等,咱们日常工作中的大部分工夫都是编写这个层面的代码。binding代码或者三方插件(js 或 C/C++ 代码)胶水代码,可能让js调用C/C++的代码。能够将其了解为一个桥,桥这头是js,桥那头是C/C++,通过这个桥能够让js调用C/C++。 在nodejs里,胶水代码的次要作用是把nodejs底层实现的C/C++库裸露给js环境。 三方插件是咱们本人实现的C/C++库,同时须要咱们本人实现胶水代码,将js和C/C++进行桥接。底层库nodejs的依赖库,包含赫赫有名的V8、libuv。 V8: 咱们都晓得,是google开发的一套高效javascript运行时,nodejs可能高效执行 js 代码的很大起因次要在它。 libuv:是用C语言实现的一套异步性能库,nodejs高效的异步编程模型很大水平上归功于libuv的实现,而libuv则是咱们明天重点要剖析的。 还有一些其余的依赖库 http-parser:负责解析http响应 openssl:加解密 c-ares:dns解析 npm:nodejs包管理器 ...对于nodejs不再过多介绍,大家能够自行查阅学习,接下来咱们重点要剖析的就是libuv。 libuv 架构咱们晓得,nodejs实现异步机制的外围便是libuv,libuv承当着nodejs与文件、网络等异步工作的沟通桥梁,上面这张图让咱们对libuv有个大略的印象: 这是libuv官网的一张图,很显著,nodejs的网络I/O、文件I/O、DNS操作、还有一些用户代码都是在 libuv 工作的。既然谈到了异步,那么咱们首先演绎下nodejs里的异步事件:非I/O: 定时器(setTimeout,setInterval)microtask(promise)process.nextTicksetImmediateDNS.lookupI/O: 网络I/O文件I/O一些DNS操作...网络I/O对于网络I/O,各个平台的实现机制不一样,linux 是 epoll 模型,类 unix 是 kquene 、windows 下是高效的 IOCP 实现端口、SunOs 是 event ports,libuv 对这几种网络I/O模型进行了封装。参考nodejs进阶视频解说:进入学习 文件I/O、异步DNS操作libuv外部还保护着一个默认4个线程的线程池,这些线程负责执行文件I/O操作、DNS操作、用户异步代码。当 js 层传递给 libuv 一个操作工作时,libuv 会把这个工作加到队列中。之后分两种状况: 1、线程池中的线程都被占用的时候,队列中工作就要进行排队期待闲暇线程。2、线程池中有可用线程时,从队列中取出这个工作执行,执行结束后,线程偿还到线程池,期待下个工作。同时以事件的形式告诉event-loop,event-loop接管到事件执行该事件注册的回调函数。当然,如果感觉4个线程不够用,能够在nodejs启动时,设置环境变量UV_THREADPOOL_SIZE来调整,出于零碎性能思考,libuv 规定可设置线程数不能超过128个。nodejs源码先简要介绍下nodejs的启动过程:1、调用platformInit办法 ,初始化 nodejs 的运行环境。2、调用 performance_node_start 办法,对 nodejs 进行性能统计。3、openssl设置的判断。4、调用v8_platform.Initialize,初始化 libuv 线程池。5、调用 V8::Initialize,初始化 V8 环境。6、创立一个nodejs运行实例。7、启动上一步创立好的实例。8、开始执行js文件,同步代码执行结束后,进入事件循环。9、在没有任何可监听的事件时,销毁 nodejs 实例,程序执行结束。以上就是 nodejs 执行一个js文件的全过程。接下来着重介绍第八个步骤,事件循环。 ...

October 31, 2022 · 3 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。 ...

October 31, 2022 · 3 min · jiezi

关于node.js:koa实战

我的项目初始化// 初始化我的项目,生成package.jsonnpm init指定入口文件 main.js我的项目的根底搭建创立 src 工作目录 创立 main.js 主入口文件 在 main.js 中引入 koa const koa = require('koa')const app = new Koa()app.listen(3000, () => { // 监听胜利的回调 console.log('server is running:http://localhost:3000')})node main.js 后即可通过拜访 http://localhost:3000,拜访到此我的项目我的项目的根本优化主动重启 // 热更新,只在开发模式下才会用的到npm install nodemon -D这时候咱们装置的 nodemon 会在 package.json 中的 devDependencies 下 批改 script 选项 "scripts":{ "dev":"nodemon ./src/main.js"}应用 nodemon 启动,开发过程中的改变会主动重启配置文件 咱们开发的过程中还须要辨别环境,开发、正式、测试等// 装置dotenvnpm install dotenv -S在我的项目的根目录下创立.env文件 尽可能早的在我的项目中引入 dotenv 并进行环境变量的配置 const dotenv = require('dotenv')dotenv.config()// 通过了下面的配置,咱们在.env文件中所配置的环境变量就曾经被加载进process.env中了// 能够将环境变量导出,在须要用到的时候进行引入module.exports = process.env这样咱们就在我的项目中配置了环境变量,配置环境变量还有另外一种形式,就是在 package.json 中的 script 中配置执行的命令,并指定环境变量,这样咱们就不必新开一个文件在 js 文件中援用了增加路由// 这是一个构造函数const Router = require('koa-router')const router = new Router({ prefix: '/user' })router.post('/register', (ctx, next) => {})通过引入 koa 的路由中间件 koa-router,咱们能够设置我的项目的路由,通过在构造函数中传入prefix:'/user'能够设置路由的前缀,以作为不同功能模块的辨别目录构造的划分咱们在 main.js 中引入了 koa 启动了服务 ...

October 27, 2022 · 4 min · jiezi

关于node.js:nodejs实现jwt

jwt是json web token的简称,本文介绍它的原理,最初后端用nodejs本人实现如何为客户端生成令牌token和校验token1.为什么须要会话治理咱们用nodejs为前端或者其余服务提供resful接口时,http协定他是一个无状态的协定,有时候咱们须要依据这个申请的高低获取具体的用户是否有权限,针对用户的上下文进行操作。所以呈现了cookies session还有jwt这几种技术的呈现, 都是对HTTP协定的一个补充。使得咱们能够用HTTP协定+状态治理构建一个的面向用户的WEB利用。 2.session和cookiessession和cookies是有分割的,session就是服务端在客户端cookies种下的session_id, 服务端保留session_id所对应的以后用户所有的状态信息。每次客户端申请服务端都带上cookies中的session_id, 服务端判断是否有具体的用户信息,如果没有就去调整登录。 cookies安全性不好,攻击者能够通过获取本地cookies进行坑骗或者利用cookies进行CSRF攻打。cookies在多个域名下,会存在跨域问题session的信息是保留在服务端下面的,当咱们node.js在stke部署多台机器的时候,须要解决共享session,所以引出来session长久化问题,所以session不反对分布式架构,无奈反对横向扩大,只能通过数据库来保留会话数据实现共享。如果长久层失败会呈现认证失败。3.jwt的定义jwt是json web token的全称,他解决了session以上的问题,长处是服务器不保留任何会话数据,即服务器变为无状态,使其更容易扩大,什么状况下应用jwt比拟适合,我感觉就是受权这个场景,因为jwt应用起来轻便,开销小,后端无状态,所以应用比拟宽泛。 4.jwt的原理JWT 的原理是,服务器认证当前,生成一个 JSON 对象,发回给用户,就像上面这样。 { "姓名": "张三", "角色": "管理员", "到期工夫": "2018年7月1日0点0分"}当前,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器齐全只靠这个对象认定用户身份。为了避免用户篡改数据,服务器在生成这个对象的时候,会加上签名。 5.jwt的认证流程流程阐明:浏览器发动申请登陆,携带用户名和明码;服务端依据用户名和明码到数据库验证身份,依据算法,将用户标识符打包生成 token,服务器返回JWT信息给浏览器,JWT不应该蕴含敏感信息,这是很重要的一点浏览器发动申请获取用户材料,把刚刚拿到的 token一起发送给服务器,个别放在header外面,字段为authorization服务器发现数据中有 token,decode token的信息,而后再次签名,验明正身;服务器返回该用户的用户材料;服务器能够在payload设置过期工夫, 如果过期了,能够让客户端从新发动验证。6.jwt的数据结构jwt蕴含了应用.格调的三个局部 Header头部{ "alg": "HS256", "typ": "JWT"} // algorithm => HMAC SHA256// type => JWT这是固定的写法,alg外表要用的是HS256算法 Payload 负载、载荷,JWT 规定了7个官网字段iss (issuer):签发人exp (expiration time):过期工夫sub (subject):主题aud (audience):受众nbf (Not Before):失效工夫iat (Issued At):签发工夫jti (JWT ID):编号除了这七个,能够自定义,比方过期工夫 Signature 签名对前两局部header和payload进行签名,避免数据篡改 HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)secret是一段字符串,后端保留,须要留神的是JWT 作为一个令牌(token),有些场合可能会放到 URL(比方 api.example.com/?token=xxx)。Base64 有三个字符+、/和=,在 URL 外面有非凡含意,所以要被替换掉:=被省略、+替换成-,/替换成_ 。这就是 Base64URL 算法。 ...

October 27, 2022 · 2 min · jiezi

关于node.js:Nodejs相关ORM框架分析

概述写这篇blog的起因,想找个node的ORM框架用用,确很难找到一篇比照剖析这些ORM框架的文章,惟一找到了一篇,竟然是通过star数来论英雄,我觉着很难服众,于是就找几个看看。起初又不想剖析,因为我发现node这种横蛮成长,滋生这些ORM轮子亘古未有,远比我设想的多;起初又觉着能够写,作为一个java出身业余钻研node的就想通过java的ORM框架来洞悉node这群ORM框架的是非曲直,于是挑了几个框架小扯一篇。 ORM框架ORM框架:Object Relational Mapping,对象-关系-映射,所以说ORM框架就是用面向对象的形式和目前的关系型数据库做匹配,java开发者目前支流的hibernate、mybatis很相熟了,JDBC原始驱动的形式想必也不在成为支流了。上面介绍几款node的ORM框架,介绍之前先介绍ORM的两种模式: Active Record 模式:流动记录模式,畛域模型模式一个模型类对应关系型数据库中的一个表,模型类的一个实例对应表中的一行记录。这个不难理解,比较简单,然而不够灵便,再看另一种模式,比拟一下 Data Mapper 模式:数据映射模式,畛域模型对象和数据表是松耦合关系,只进行业务逻辑的解决,和数据层解耦。须要一个实体管理器来将模型和长久化层做对应,这样一来,灵活性就高,当然复杂性也减少了。 所以说,Data Mapper模式对业务代码干涉少,Active Record模式间接在对象上CRUD,代码编写也更不便,这就像hibernate和mybatis两种框架,如果想深入研究,能够理解一下 有这么一句话很认同,ActiveRecord更加适宜疾速开发成型的短期简略我的项目,而DataMapper更加适宜长线开发,放弃业务逻辑与数据存储独立的简单我的项目。除此之外,技术选型还要思考其余因素,比方我的项目历史背景等等。 TypeORMTypeORM 是一个 ORM 框架,具体介绍见 TypeORM 官网介绍,TypeORM 也借鉴了hibernate,所以你会发现它特地相熟,尤其是装璜类的形式。 闲话少说,间接用CLI 命令疾速构建我的项目 npm install typeorm -g创立我的项目 typeorm init --name MyProject --database mysqlname 是我的项目的名称,database 是将应用的数据库,TypeORM 反对多种数据库。 生成文档构造 MyProject├── src // TypeScript 代码│ ├── entity // 存储实体(数据库模型)的地位│ │ └── User.ts // 示例 entity│ ├── migration // 存储迁徙的目录│ └── index.ts // 程序执行主文件├── .gitignore // gitignore文件├── ormconfig.json // ORM和数据库连贯配置├── package.json // node module 依赖├── README.md // 简略的 readme 文件└── tsconfig.json // TypeScript 编译选项批改 ormconfig.json 数据库配置文件,间接运行就能够了 ...

October 26, 2022 · 3 min · jiezi

关于node.js:NodejsESModule和commonjs傻傻分不清

最近写nodejs脚本的时候遇到了commonjs和ESModule的问题,正好之前用得稀里糊涂的,这次好好学习一下。 ES Module导出仅导出named exports: 命名导出,每次能够导出一个或者多个。default exports: 默认导出,每次只能存在一个。以上两者能够混合导出。 // 命名导出 export const b = 'b' // 默认导出 export default { a: 1 }; const c = 'c' export { c } // 以上内容会合并导出,即导出为: {b:'b', c:'c', default: {a:1}}更多示例能够间接去看mdn 重导出(re-exporting / aggregating)算是一个导入再导出的一个语法糖吧。 export { default as function1, function2, } from 'bar.js'; // 等价于 import { default as function1, function2 } from 'bar.js'; export { function1, function2 };然而这种语法是会报错的: export DefaultExport from 'bar.js'; // Invalid正确的语法应该是: ...

October 26, 2022 · 3 min · jiezi

关于node.js:Nodejs实现大文件断点续传

前言平时业务需要:上传图片、Excel等,毕竟几M的大小能够很快就上传到服务器。 针对于上传视频等大文件几百M或者几G的大小,就须要期待比拟长的工夫。 这就产生了对应的解决办法,对于大文件上传时的暂停、断网、网络较差的状况下, 应用切片+断点续传就可能很好的应答上述的状况 计划剖析切片 就是对上传视频进行切分,具体操作为:File.slice(start,end):返回新的blob对象 拷贝blob的起始字节拷贝blob的完结字节断点续传 每次切片上传之前,申请服务器接口,读取雷同文件的已上传切片数上传的是新文件,服务端则返回0,否则返回已上传切片数具体解决流程该demo提供关键点思路及办法,其余性能如:文件限度,lastModifiedDate校验文件重复性,缓存文件定期革除等性能扩大都能够在此代码根底上增加。 html 局部<input class="video" type="file" /><button type="submit" onclick="handleVideo(event, '.video', 'video')"> 提交</button>script 局部let count = 0; // 记录须要上传的文件下标const handleVideo = async (event, name, url) => {// 阻止浏览器默认表单事件event.preventDefault();let currentSize = document.querySelector("h2");let files = document.querySelector(name).files;// 默认切片数量const sectionLength = 100;// 首先申请接口,获取服务器是否存在此文件// count为0则是第一次上传,count不为0则服务器存在此文件,返回已上传的切片数count = await handleCancel(files[0]);// 申明寄存切片的数组对象let fileCurrent = [];// 循环file文件对象for (const file of [...files]) { // 得出每个切片的大小 let itemSize = Math.ceil(file.size / sectionLength); // 循环文件size,文件blob存入数组 let current = 0; for (current; current < file.size; current += itemSize) { fileCurrent.push({ file: file.slice(current, current + itemSize) }); } // axios模仿手动勾销申请 const CancelToken = axios.CancelToken; const source = CancelToken.source(); // 当断点续传时,解决切片数量,已上传切片则不须要再次申请上传 fileCurrent = count === 0 ? fileCurrent : fileCurrent.slice(count, sectionLength); // 循环切片申请接口 for (const [index, item] of fileCurrent.entries()) { // 模仿申请暂停 || 网络断开 if (index > 90) { source.cancel("勾销申请"); } // 存入文件相干信息 // file为切片blob对象 // filename为文件名 // index为以后切片数 // total为总切片数 let formData = new FormData(); formData.append("file", item.file); formData.append("filename", file.name); formData.append("total", sectionLength); formData.append("index", index + count + 1); await axios({ url: `http://localhost:8080/${url}`, method: "POST", data: formData, cancelToken: source.token, }) .then((response) => { // 返回数据显示进度 currentSize.innerHTML = `进度${response.data.size}%`; }) .catch((err) => { console.log(err); }); }}};// 申请接口,查问上传文件是否存在// count为0示意不存在,count不为0则已上传对应切片数const handleCancel = (file) => {return axios({ method: "post", url: "http://localhost:8080/getSize", headers: { "Content-Type": "application/json; charset = utf-8" }, data: { fileName: file.name, },}) .then((res) => { return res.data.count; }) .catch((err) => { console.log(err); });};参考nodejs进阶视频解说:进入学习 ...

October 25, 2022 · 3 min · jiezi

关于node.js:NodejsRedis实现简易消息队列

前言音讯队列是存储数据的一个中间件,能够了解为一个容器。生产者生产音讯投递 到队列中,消费者能够拉取音讯进行生产,如果消费者目前没有生产的打算,则音讯队列会保留音讯,直到消费者有生产的打算。 设计思路生产者连贯 redis向指定通道 通过 lpush 音讯消费者连贯 redis死循环通过 brpop 阻塞式获取音讯拿到音讯进行生产循环拿去下一个音讯Redis装置及启动此步骤各位道友随便就好,不肯定要用docker 。只有保障本人能连贯到redis 服务即可。# 应用docker 拉取redis 镜像docker pull redis:latest# 启动redis服务 # --name 前面是容器名字不便后续保护和治理 # -p 前面是指映射容器服务的 6379 端口到宿主机的 6379 端口docker run -itd --name redis-mq -p 6379:6379 redis# ============ docker 罕用基本操作(题外话) =================# 拉取镜像docker pull 镜像名称 # 查看镜像docker images# 删除镜像docker rmi 镜像名称# 查看运行容器(仅为启动中的)docker ps # 查看运行容器(蕴含未启动)docker ps -a# 启动容器docker start 容器名称/容器id# 进行容器docker stop 容器名称/容器idNodejs连贯初始化工程 # 创立文件夹并进入mkdir queue-node-redis && cd queue-node-redis# yarn 初始化yarn init -y# 下载redis包,# 指定版本的起因是尽量减少道友们的失败几率 毕竟前端的工具迭代太快了yarn add [email protected] 创立 lib 与 utils 目录 ...

October 25, 2022 · 3 min · jiezi

关于node.js:koa实战

我的项目初始化// 初始化我的项目,生成package.jsonnpm init指定入口文件 main.js我的项目的根底搭建创立 src 工作目录 创立 main.js 主入口文件 在 main.js 中引入 koa const koa = require('koa')const app = new Koa()app.listen(3000, () => { // 监听胜利的回调 console.log('server is running:http://localhost:3000')})node main.js 后即可通过拜访 http://localhost:3000,拜访到此我的项目我的项目的根本优化主动重启 // 热更新,只在开发模式下才会用的到npm install nodemon -D这时候咱们装置的 nodemon 会在 package.json 中的 devDependencies 下 批改 script 选项 "scripts":{ "dev":"nodemon ./src/main.js"}应用 nodemon 启动,开发过程中的改变会主动重启配置文件 咱们开发的过程中还须要辨别环境,开发、正式、测试等// 装置dotenvnpm install dotenv -S在我的项目的根目录下创立.env文件 尽可能早的在我的项目中引入 dotenv 并进行环境变量的配置 const dotenv = require('dotenv')dotenv.config()// 通过了下面的配置,咱们在.env文件中所配置的环境变量就曾经被加载进process.env中了// 能够将环境变量导出,在须要用到的时候进行引入module.exports = process.env这样咱们就在我的项目中配置了环境变量,配置环境变量还有另外一种形式,就是在 package.json 中的 script 中配置执行的命令,并指定环境变量,这样咱们就不必新开一个文件在 js 文件中援用了增加路由// 这是一个构造函数const Router = require('koa-router')const router = new Router({ prefix: '/user' })router.post('/register', (ctx, next) => {})通过引入 koa 的路由中间件 koa-router,咱们能够设置我的项目的路由,通过在构造函数中传入prefix:'/user'能够设置路由的前缀,以作为不同功能模块的辨别目录构造的划分咱们在 main.js 中引入了 koa 启动了服务 ...

October 21, 2022 · 4 min · jiezi

关于node.js:NodejsESModule和commonjs傻傻分不清

久没有更新博客了,最近写nodejs脚本的时候遇到了commonjs和ESModule的问题,正好之前用得稀里糊涂的,这次好好学习一下。 ES Module导出仅导出named exports: 命名导出,每次能够导出一个或者多个。default exports: 默认导出,每次只能存在一个。以上两者能够混合导出。 // 命名导出 export const b = 'b' // 默认导出 export default { a: 1 }; const c = 'c' export { c } // 以上内容会合并导出,即导出为: {b:'b', c:'c', default: {a:1}}更多示例能够间接去看mdn 重导出(re-exporting / aggregating)算是一个导入再导出的一个语法糖吧。 export { default as function1, function2, } from 'bar.js'; // 等价于 import { default as function1, function2 } from 'bar.js'; export { function1, function2 };然而这种语法是会报错的: export DefaultExport from 'bar.js'; // Invalid正确的语法应该是: ...

October 21, 2022 · 3 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。 ...

October 21, 2022 · 3 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 最初一部分的字符串完结,无扩展名则返回空留神: ...

October 21, 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 功不可没。 ...

October 18, 2022 · 8 min · jiezi

关于node.js:nodejs实现jwt

jwt是json web token的简称,本文介绍它的原理,最初后端用nodejs本人实现如何为客户端生成令牌token和校验token1.为什么须要会话治理咱们用nodejs为前端或者其余服务提供resful接口时,http协定他是一个无状态的协定,有时候咱们须要依据这个申请的高低获取具体的用户是否有权限,针对用户的上下文进行操作。所以呈现了cookies session还有jwt这几种技术的呈现, 都是对HTTP协定的一个补充。使得咱们能够用HTTP协定+状态治理构建一个的面向用户的WEB利用。 2.session和cookiessession和cookies是有分割的,session就是服务端在客户端cookies种下的session_id, 服务端保留session_id所对应的以后用户所有的状态信息。每次客户端申请服务端都带上cookies中的session_id, 服务端判断是否有具体的用户信息,如果没有就去调整登录。 cookies安全性不好,攻击者能够通过获取本地cookies进行坑骗或者利用cookies进行CSRF攻打。cookies在多个域名下,会存在跨域问题session的信息是保留在服务端下面的,当咱们node.js在stke部署多台机器的时候,须要解决共享session,所以引出来session长久化问题,所以session不反对分布式架构,无奈反对横向扩大,只能通过数据库来保留会话数据实现共享。如果长久层失败会呈现认证失败。3.jwt的定义jwt是json web token的全称,他解决了session以上的问题,长处是服务器不保留任何会话数据,即服务器变为无状态,使其更容易扩大,什么状况下应用jwt比拟适合,我感觉就是受权这个场景,因为jwt应用起来轻便,开销小,后端无状态,所以应用比拟宽泛。 4.jwt的原理JWT 的原理是,服务器认证当前,生成一个 JSON 对象,发回给用户,就像上面这样。 { "姓名": "张三", "角色": "管理员", "到期工夫": "2018年7月1日0点0分"}当前,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器齐全只靠这个对象认定用户身份。为了避免用户篡改数据,服务器在生成这个对象的时候,会加上签名。 5.jwt的认证流程流程阐明:浏览器发动申请登陆,携带用户名和明码;服务端依据用户名和明码到数据库验证身份,依据算法,将用户标识符打包生成 token,服务器返回JWT信息给浏览器,JWT不应该蕴含敏感信息,这是很重要的一点浏览器发动申请获取用户材料,把刚刚拿到的 token一起发送给服务器,个别放在header外面,字段为authorization服务器发现数据中有 token,decode token的信息,而后再次签名,验明正身;服务器返回该用户的用户材料;服务器能够在payload设置过期工夫, 如果过期了,能够让客户端从新发动验证。6.jwt的数据结构jwt蕴含了应用.格调的三个局部 Header头部{ "alg": "HS256", "typ": "JWT"} // algorithm => HMAC SHA256// type => JWT这是固定的写法,alg外表要用的是HS256算法 Payload 负载、载荷,JWT 规定了7个官网字段iss (issuer):签发人exp (expiration time):过期工夫sub (subject):主题aud (audience):受众nbf (Not Before):失效工夫iat (Issued At):签发工夫jti (JWT ID):编号除了这七个,能够自定义,比方过期工夫 Signature 签名对前两局部header和payload进行签名,避免数据篡改 HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)secret是一段字符串,后端保留,须要留神的是JWT 作为一个令牌(token),有些场合可能会放到 URL(比方 api.example.com/?token=xxx)。Base64 有三个字符+、/和=,在 URL 外面有非凡含意,所以要被替换掉:=被省略、+替换成-,/替换成_ 。这就是 Base64URL 算法。 ...

October 18, 2022 · 2 min · jiezi

关于node.js:Nodejs相关ORM框架分析

概述写这篇blog的起因,想找个node的ORM框架用用,确很难找到一篇比照剖析这些ORM框架的文章,惟一找到了一篇,竟然是通过star数来论英雄,我觉着很难服众,于是就找几个看看。起初又不想剖析,因为我发现node这种横蛮成长,滋生这些ORM轮子亘古未有,远比我设想的多;起初又觉着能够写,作为一个java出身业余钻研node的就想通过java的ORM框架来洞悉node这群ORM框架的是非曲直,于是挑了几个框架小扯一篇。 ORM框架ORM框架:Object Relational Mapping,对象-关系-映射,所以说ORM框架就是用面向对象的形式和目前的关系型数据库做匹配,java开发者目前支流的hibernate、mybatis很相熟了,JDBC原始驱动的形式想必也不在成为支流了。上面介绍几款node的ORM框架,介绍之前先介绍ORM的两种模式: Active Record 模式:流动记录模式,畛域模型模式一个模型类对应关系型数据库中的一个表,模型类的一个实例对应表中的一行记录。这个不难理解,比较简单,然而不够灵便,再看另一种模式,比拟一下 Data Mapper 模式:数据映射模式,畛域模型对象和数据表是松耦合关系,只进行业务逻辑的解决,和数据层解耦。须要一个实体管理器来将模型和长久化层做对应,这样一来,灵活性就高,当然复杂性也减少了。 所以说,Data Mapper模式对业务代码干涉少,Active Record模式间接在对象上CRUD,代码编写也更不便,这就像hibernate和mybatis两种框架,如果想深入研究,能够理解一下 有这么一句话很认同,ActiveRecord更加适宜疾速开发成型的短期简略我的项目,而DataMapper更加适宜长线开发,放弃业务逻辑与数据存储独立的简单我的项目。除此之外,技术选型还要思考其余因素,比方我的项目历史背景等等。 TypeORMTypeORM 是一个 ORM 框架,具体介绍见 TypeORM 官网介绍,TypeORM 也借鉴了hibernate,所以你会发现它特地相熟,尤其是装璜类的形式。 闲话少说,间接用CLI 命令疾速构建我的项目 npm install typeorm -g创立我的项目 typeorm init --name MyProject --database mysqlname 是我的项目的名称,database 是将应用的数据库,TypeORM 反对多种数据库。 生成文档构造 MyProject├── src // TypeScript 代码│ ├── entity // 存储实体(数据库模型)的地位│ │ └── User.ts // 示例 entity│ ├── migration // 存储迁徙的目录│ └── index.ts // 程序执行主文件├── .gitignore // gitignore文件├── ormconfig.json // ORM和数据库连贯配置├── package.json // node module 依赖├── README.md // 简略的 readme 文件└── tsconfig.json // TypeScript 编译选项批改 ormconfig.json 数据库配置文件,间接运行就能够了 ...

October 17, 2022 · 3 min · jiezi

关于node.js:NodejsRedis实现简易消息队列

前言音讯队列是存储数据的一个中间件,能够了解为一个容器。生产者生产音讯投递 到队列中,消费者能够拉取音讯进行生产,如果消费者目前没有生产的打算,则音讯队列会保留音讯,直到消费者有生产的打算。 设计思路生产者连贯 redis向指定通道 通过 lpush 音讯消费者连贯 redis死循环通过 brpop 阻塞式获取音讯拿到音讯进行生产循环拿去下一个音讯Redis装置及启动此步骤各位道友随便就好,不肯定要用docker 。只有保障本人能连贯到redis 服务即可。# 应用docker 拉取redis 镜像docker pull redis:latest# 启动redis服务 # --name 前面是容器名字不便后续保护和治理 # -p 前面是指映射容器服务的 6379 端口到宿主机的 6379 端口docker run -itd --name redis-mq -p 6379:6379 redis# ============ docker 罕用基本操作(题外话) =================# 拉取镜像docker pull 镜像名称 # 查看镜像docker images# 删除镜像docker rmi 镜像名称# 查看运行容器(仅为启动中的)docker ps # 查看运行容器(蕴含未启动)docker ps -a# 启动容器docker start 容器名称/容器id# 进行容器docker stop 容器名称/容器idNodejs连贯初始化工程 # 创立文件夹并进入mkdir queue-node-redis && cd queue-node-redis# yarn 初始化yarn init -y# 下载redis包,# 指定版本的起因是尽量减少道友们的失败几率 毕竟前端的工具迭代太快了yarn add [email protected] 创立 lib 与 utils 目录 ...

October 17, 2022 · 3 min · jiezi

关于node.js:一文读懂NodeJs知识体系和原理浅析

node.js 初探Node.js 是一个 JS 的服务端运行环境,简略的来说,它是在 JS 语言标准的根底上,封装了一些服务端的运行时对象,让咱们可能简略实现十分多的业务性能。 如果咱们只应用 JS 的话,实际上只是能进行一些简略的逻辑运算。node.js 就是基于 JS 语法减少与操作系统之间的交互。 node.js 的装置咱们能够应用多种形式来装置 node.js,node.js 实质上也是一种软件,咱们能够应用间接下载二进制安装文件装置,通过零碎包治理进行装置或者通过源码自行编译均可。 一般来讲,对于集体开发的电脑,咱们举荐间接通过 node.js 官网的二进制安装文件来装置。对于打包上线的一些 node.js 环境,也能够通过二进制编译的模式来装置。 装置胜利之后,咱们的 node 命令就会主动退出咱们的零碎环境变量 path 中,咱们就能间接在全局应用 node 命令拜访到咱们方才装置的 node 可执行命令行工具。 node.js 版本切换在个人电脑上,咱们能够装置一些工具,对 node.js 版本进行切换,例如 nvm 和 n。 nvm 的全称就是 node version manager,意思就是可能治理 node 版本的一个工具,它提供了一种间接通过 shell 执行的形式来进行装置。简略来说,就是通过将多个 node 版本装置在指定门路,而后通过 nvm 命令切换时,就会切换咱们环境变量中 node 命令指定的理论执行的软件门路。装置胜利之后,咱们就能在以后的操作系统中应用多个 node.js 版本。 包管理工具 npmcurl -o- https://raw.githubusercontent.com/nvm- sh/nvm/v0.35.3/install.sh | bash 咱们对 npm 应该都比拟相熟了,它是 node.js 内置的一款工具,目标在于装置和公布合乎 node.js 规范的模块,从而实现社区共建的目标凋敝整个社区。 ...

October 17, 2022 · 11 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 同一个文件,共享文件偏移量和文件状态 ...

October 17, 2022 · 5 min · jiezi

关于node.js:Nodejs工程师养成计划圣安地列斯

download:Node.js工程师养成打算圣安地列斯JVM运行时数据区1什么是JVM?JVM能够了解为一种标准。任何高级语言,只有能生成,都能够交给JVM加载执行。类文件。所以不论是Java还是Kotlin,尽管JVM叫Java虚拟机,然而Kotlin会被编译成。由编译器生成并由JVM加载的类文件。所以即便在日常开发工作中应用Kotlin,也须要把握JVM的原理。JVM次要由三局部组成:类加载器、运行时数据区和执行引擎。类加载器:将编译后的类文件加载到JVM内存中;运行时数据区:次要指文章结尾的JVM内存模型,用于存储程序执行过程中产生的数据;执行引擎:执行字节码指令会和运行时数据区交互,生成的数据会存储在运行时数据区。 2运行时数据区-堆栈内存本节重点介绍JVM运行时数据区,它次要分为两局部,堆和栈。2.1堆和栈的职责依据程序运行时的性能,堆是运行时的存储单元,栈是运行时的处理单元。也就是说,堆是为了解决数据存储的问题。数据应该存在于哪里?怎么挽回?堆栈是解决程序运行的问题,如何执行程序,如何解决数据,如何执行办法等。2.2程序计数器程序计数器也是寄存器,是惟一不会造成内存透露的区域;它的次要性能是记录多线程场景中的代码执行地位。首先,咱们来看一个简略的办法。 公共动态void getByteCode() {int a = 10int b = 20int c = a+b;}复制代码当这个办法在JVM中执行时,字节码指令是: 0双脉冲102 istore_03双推205 istore_16 iload_07 iload_18 iadd9 istore_210返回复制代码如果有相熟CPU工夫片轮换机制的搭档,应该晓得程序的运行工夫是会切片的,每一段都是一个CPU工夫片。对象创立的过程在日常开发工作中,咱们罕用的创建对象的形式次要分为以下几种:(1)由new关键字创立;(2)通过反思;(3)通过clone的办法,obj.clone;(4)序列化或反序列化接下来,咱们以alloc办法为例,看看类是如何被字节码创立的:`0新的#83 dup4调用非凡#97 astore_08返回`

October 16, 2022 · 1 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给父过程发送数据。 ...

October 10, 2022 · 4 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会在这个阶段执行;事件循环详解 ...

October 10, 2022 · 4 min · jiezi

关于node.js:说说Nodejs高并发的原理

写在后面咱们先来看几个常见的说法 nodejs是单线程 + 非阻塞I/O模型nodejs适宜高并发nodejs适宜I/O密集型利用,不适宜CPU密集型利用在具体分析这几个说法是不是、为什么之前,咱们先来做一些筹备工作 从头聊起一个常见web利用会做哪些事件运算(执行业务逻辑、数学运算、函数调用等。次要工作在CPU进行)I/O(如读写文件、读写数据库、读写网络申请等。次要工作在各种I/O设施,如磁盘、网卡等)一个典型的传统web利用实现多过程,一个申请fork一个(子)过程 + 阻塞I/O(即blocking I/O或BIO)多线程,一个申请创立一个线程 + 阻塞I/O多过程web利用示例伪代码 listenFd = new Socket(); // 创立监听socketBind(listenFd, 80); // 绑定端口Listen(listenFd); // 开始监听for ( ; ; ) { // 接管客户端申请,通过新的socket建设连贯 connFd = Accept(listenFd); // fork子过程 if ((pid = Fork()) === 0) { // 子过程中 // BIO读取网络申请数据,阻塞,产生过程调度 request = connFd.read(); // BIO读取本地文件,阻塞,产生过程调度 content = ReadFile('test.txt'); // 将文件内容写入响应 Response.write(content); }}多线程利用实际上和多过程相似,只不过将一个申请调配一个过程换成了一个申请调配一个线程。线程比照过程更轻量,在系统资源占用上更少,上下文切换(ps:所谓上下文切换,略微解释一下:单核心CPU的状况下同一时间只能执行一个过程或线程中的工作,而为了宏观上的并行,则须要在多个过程或线程之间按工夫片来回切换以保障各进、线程都有机会被执行)的开销也更小;同时线程间更容易共享内存,便于开发 上文中提到了web利用的两个外围要点,一个是进(线)程模型,一个是I/O模型。那阻塞I/O到底是什么?又有哪些其余的I/O模型呢?别着急,首先咱们看一下什么是阻塞 什么是阻塞?什么是阻塞I/O?简而言之,阻塞是指函数调用返回之前,当后退(线)程会被挂起,进入期待状态,在这个状态下,当后退(线)程暂停运行,引起CPU的进(线)程调度。函数只有在外部工作全副执行实现后才会返回给调用者 所以阻塞I/O是,应用程序通过API调用I/O操作后,当后退(线)程将会进入期待状态,代码无奈持续往下执行,这时CPU能够进行进(线)程调度,即切换到其余可执行的进(线)程继续执行,当后退(线)程在底层I/O申请解决完后才会返回并能够继续执行 多进(线)程 + 阻塞I/O模型有什么问题?在理解了什么是阻塞和阻塞I/O后,咱们来剖析一下传统web利用多进(线)程 + 阻塞I/O模型有什么弊病。 因为一个申请须要调配一个进(线)程,这样的零碎在并发量大时须要保护大量进(线)程,且须要进行大量的上下文切换,这都须要大量的CPU、内存等系统资源撑持,所以在高并发申请进来时CPU和内存开销会急剧回升,可能会迅速拖垮整个零碎导致服务不可用 nodejs利用实现接下来咱们看看nodejs利用是如何实现的。 事件驱动,单线程(主线程)非阻塞I/O在官网上能够看到,nodejs最次要的两大特点,一个是单线程事件驱动,一个是“非阻塞”I/O模型。单线程 + 事件驱动比拟好了解,前端同学应该都很相熟js的单线程和事件循环这套机制了,那咱们次要来钻研一下这个“非阻塞I/O”是怎么一回事。首先来看一段nodejs服务端利用常见的代码,const net = require('net');const server = net.createServer();const fs = require('fs');server.listen(80); // 监听端口// 监听事件建设连贯server.on('connection', (socket) => { // 监听事件读取申请数据 socket.on('data', (data) => { // 异步读取本地文件 fs.readFile('test.txt', (err, data) => { // 将读取的内容写入响应 socket.write(data); socket.end(); }) });});能够看到在nodejs中,咱们能够以异步的形式去进行I/O操作,通过API调用I/O操作后会马上返回,紧接着就能够继续执行其余代码逻辑,那为什么nodejs中的I/O是“非阻塞”的呢?答复这个问题之前咱们再做一些筹备工作,参考nodejs进阶视频解说:进入学习 ...

October 10, 2022 · 1 min · jiezi

关于node.js:windows-环境下使用-Nodejs-遇到-unable-to-get-local-issuer-certificate

我有一个 OData 服务,部署在 SAP S/4HANA 服务器上,浏览器里通过如下 url,能够失常拜访到其元数据: 我编写了一个 node.js 利用,通过编程的形式拜访这个 OData 服务的元数据: var request = require('request');var url = 'https://ldai2xxx:44356/sap/opu/odata/sap/ZBOOK_MANAGE_SRV/$metadata';var oOptions = { url: url, method: 'GET' };var oPromise = new Promise(function(resolve,reject){ request.get(oOptions,function(error,response,body){ if(error){ console.log("error occurred: " + error); reject(error); } resolve(body); });});oPromise.then((data) => console.log(data));应用 node 执行下面的代码,遇到如下谬误音讯: error occurred: Error: unable to get local issuer certificate(node:33376) UnhandledPromiseRejectionWarning: Error: unable to get local issuer certificateat TLSSocket.onConnectSecure (_tls_wrap.js:1497:34)at TLSSocket.emit (events.js:315:20)at TLSSocket._finishInit (_tls_wrap.js:932:8)at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:706:12)(Use node --trace-warnings ... to show where the warning was created)(node:33376) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.ht...). (rejection id: 1)(node:33376) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. ...

October 8, 2022 · 1 min · jiezi

关于node.js:Nodejs-教程一-基本概念与基本使用

无题,说不上学习的起因,只是因为在学习打算外面而已。是什么?我在学JavaScript的时候是在浏览器面看输入和后果,所以浏览器就是JavaScript的运行环境之一。Node.js是JavaScript的另一个运行环境,基于Chrome V8引擎,开源跨平台,能够让JavaScript在浏览器之外执行,应用Node.js能够用来开发服务端应用程序。 咱们当初装下Node.js,Node.js的下载地址: https://nodejs.org/en/。 下载过后一路next,next就行。而后关上命令行输出node -v, 呈现下图代表装置胜利: 代表装置胜利。 Hello World那怎么在浏览器之外运行JavaScript? 首先你须要一个js文件, 而后在终端外面执行node js文件名即可,如下图所示: 还能帮咱们干什么?Node.js 能够帮忙咱们干啥,让咱们再去翻翻官网文档: As an asynchronous event-driven JavaScript runtime, Node.js is designed to build scalable network applications. In the following "hello world" example, many connections can be handled concurrently. Upon each connection, the callback is fired, but if there is no work to be done, Node.js will sleep. Node.js 是一个异步事件驱动JavaScript 运行时,为构建高扩大的网络应用而生,上面的“hello world”例子,能够并发解决连贯,每个连贯筹备结束,回调将会被激活。然而如果没有网络连接,node.js 将会进入“睡眠”。 我上面建设了一个app.js, 外面的代码如下: ...

October 6, 2022 · 2 min · jiezi

关于node.js:解决nvm切换nodejs版本报错乱码

在开发中切换node版本时报错: PS D:\wsp\xxxapp> nvm use 16.15.1exit status 5: exit status 1: ļ ļ 预计零碎权限的问题导致,右键管理员运行VSCode再尝试就解决了。

October 4, 2022 · 1 min · jiezi

关于node.js:Nodejs实现大文件断点续传

前言平时业务需要:上传图片、Excel等,毕竟几M的大小能够很快就上传到服务器。 针对于上传视频等大文件几百M或者几G的大小,就须要期待比拟长的工夫。 这就产生了对应的解决办法,对于大文件上传时的暂停、断网、网络较差的状况下, 应用切片+断点续传就可能很好的应答上述的状况 计划剖析切片 就是对上传视频进行切分,具体操作为:File.slice(start,end):返回新的blob对象 拷贝blob的起始字节拷贝blob的完结字节断点续传 每次切片上传之前,申请服务器接口,读取雷同文件的已上传切片数上传的是新文件,服务端则返回0,否则返回已上传切片数具体解决流程该demo提供关键点思路及办法,其余性能如:文件限度,lastModifiedDate校验文件重复性,缓存文件定期革除等性能扩大都能够在此代码根底上增加。 html 局部<input class="video" type="file" /><button type="submit" onclick="handleVideo(event, '.video', 'video')"> 提交</button>script 局部let count = 0; // 记录须要上传的文件下标const handleVideo = async (event, name, url) => {// 阻止浏览器默认表单事件event.preventDefault();let currentSize = document.querySelector("h2");let files = document.querySelector(name).files;// 默认切片数量const sectionLength = 100;// 首先申请接口,获取服务器是否存在此文件// count为0则是第一次上传,count不为0则服务器存在此文件,返回已上传的切片数count = await handleCancel(files[0]);// 申明寄存切片的数组对象let fileCurrent = [];// 循环file文件对象for (const file of [...files]) { // 得出每个切片的大小 let itemSize = Math.ceil(file.size / sectionLength); // 循环文件size,文件blob存入数组 let current = 0; for (current; current < file.size; current += itemSize) { fileCurrent.push({ file: file.slice(current, current + itemSize) }); } // axios模仿手动勾销申请 const CancelToken = axios.CancelToken; const source = CancelToken.source(); // 当断点续传时,解决切片数量,已上传切片则不须要再次申请上传 fileCurrent = count === 0 ? fileCurrent : fileCurrent.slice(count, sectionLength); // 循环切片申请接口 for (const [index, item] of fileCurrent.entries()) { // 模仿申请暂停 || 网络断开 if (index > 90) { source.cancel("勾销申请"); } // 存入文件相干信息 // file为切片blob对象 // filename为文件名 // index为以后切片数 // total为总切片数 let formData = new FormData(); formData.append("file", item.file); formData.append("filename", file.name); formData.append("total", sectionLength); formData.append("index", index + count + 1); await axios({ url: `http://localhost:8080/${url}`, method: "POST", data: formData, cancelToken: source.token, }) .then((response) => { // 返回数据显示进度 currentSize.innerHTML = `进度${response.data.size}%`; }) .catch((err) => { console.log(err); }); }}};// 申请接口,查问上传文件是否存在// count为0示意不存在,count不为0则已上传对应切片数const handleCancel = (file) => {return axios({ method: "post", url: "http://localhost:8080/getSize", headers: { "Content-Type": "application/json; charset = utf-8" }, data: { fileName: file.name, },}) .then((res) => { return res.data.count; }) .catch((err) => { console.log(err); });};相干nodejs进阶视频解说:进入学习node服务端 局部// 应用express构建服务器apiconst express = require("express");// 引入上传文件逻辑代码const upload = require("./upload_file");// 解决所有响应,设置跨域app.all("*", (req, res, next) => { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "X-Requested-With"); res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS"); res.header("Access-Control-Allow-Headers", "Content-Type, X-Requested-With "); res.header("X-Powered-By", " 3.2.1"); res.header("Content-Type", "application/json;charset=utf-8"); next();});const app = express();app.use(bodyParser.json({ type: "application/*+json" }));// 视频上传(查问以后切片数)app.post("/getSize", upload.getSize);// 视频上传接口app.post("/video", upload.video);// 开启本地端口侦听app.listen(8080);upload_file// 文件上传模块const formidable = require("formidable");// 文件系统模块const fs = require("fs");// 零碎门路模块const path = require("path");// 操作写入文件流const handleStream = (item, writeStream) => { // 读取对应目录文件buffer const readFile = fs.readFileSync(item); // 将读取的buffer || chunk写入到stream中 writeStream.write(readFile); // 写入完后,革除暂存的切片文件 fs.unlink(item, () => {});};// 视频上传(切片)module.exports.video = (req, res) => { // 创立解析对象 const form = new formidable.IncomingForm(); // 设置视频文件上传门路 let dirPath = path.join(__dirname, "video"); form.uploadDir = dirPath; // 是否保留上传文件名后缀 form.keepExtensions = true; // err 谬误对象 如果解析失败蕴含错误信息 // fields 蕴含除了二进制以外的formData的key-value对象 // file 对象类型 上传文件的信息 form.parse(req, async (err, fields, file) => { // 获取上传文件blob对象 let files = file.file; // 获取以后切片index let index = fields.index; // 获取总切片数 let total = fields.total; // 获取文件名 let filename = fields.filename; // 重写上传文件名,设置暂存目录 let url = dirPath + "/" + filename.split(".")[0] + `_${index}.` + filename.split(".")[1]; try { // 同步批改上传文件名 fs.renameSync(files.path, url); console.log(url); // 异步解决 setTimeout(() => { // 判断是否是最初一个切片上传实现,拼接写入全副视频 if (index === total) { // 同步创立新目录,用以寄存残缺视频 let newDir = __dirname + `/uploadFiles/${Date.now()}`; // 创立目录 fs.mkdirSync(newDir); // 创立可写流,用以写入文件 let writeStream = fs.createWriteStream(newDir + `/${filename}`); let fsList = []; // 取出所有切片文件,放入数组 for (let i = 0; i < total; i++) { const fsUrl = dirPath + "/" + filename.split(".")[0] + `_${i + 1}.` + filename.split(".")[1]; fsList.push(fsUrl); } // 循环切片文件数组,进行stream流的写入 for (let item of fsList) { handleStream(item, writeStream); } // 全副写入,敞开stream写入流 writeStream.end(); } }, 100); } catch (e) { console.log(e); } res.send({ code: 0, msg: "上传胜利", size: index, }); });};// 获取文件切片数module.exports.getSize = (req, res) => { let count = 0; req.setEncoding("utf8"); req.on("data", function (data) { let name = JSON.parse(data); let dirPath = path.join(__dirname, "video"); // 计算已上传的切片文件个数 let files = fs.readdirSync(dirPath); files.forEach((item, index) => { let url = name.fileName.split(".")[0] + `_${index + 1}.` + name.fileName.split(".")[1]; if (files.includes(url)) { ++count; } }); res.send({ code: 0, msg: "请持续上传", count, }); });};逻辑剖析前端 ...

October 3, 2022 · 3 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 事件中,革除一些曾经调配的资源(文件描述符、句柄等),不举荐在其中重启过程。 ...

October 3, 2022 · 3 min · jiezi

关于node.js:nodejs-childprocess-模块用法总结

调用内部程序的四个异步办法别离是:execFile, spawn, exec 和 fork,四个办法的返回值都是 ChildProcess 实例,ChildProcess 实例领有 Process 的一部分罕用性能,例如:pid, stdin, stdout, stderr,等。他们的具体用法以及区别如下: execFile能够调用 js 脚本代码(执行 node a.js),也能够调用其余类型的程序;父子过程不拆散,且不可设为父子过程拆散,基于回调 Buffer 获取子过程输入;父子过程能够应用信号量通信;spawn能够调用 js 脚本代码(执行 node a.js),也能够调用其余类型的程序;默认父子过程不拆散,能够设为父子过程拆散,基于流获取子过程输入;父子过程能够应用信号量通信;exec能够调用 js 脚本代码(执行 node a.js),也能够调用其余类型的程序;能够应用 shell 外壳的一些用法,例如:重定向,管道操作,通配符,等;父子过程不拆散,且不可设为父子过程拆散,基于回调 Buffer 获取子过程输入;父子过程能够应用信号量通信;forkfork 办法只能调用 js 脚本代码,或者说专门用来调用 js 脚本代码,非 js 脚本的其余程序,不能调用;fork 办法默认父子过程拆散,并基于流获取子过程输入;因为父子过程拆散,所以子过程的流默认重定向到控制台;不须要像 spawn(detach=false),通过 pipe 调用将子过程的流重定向到父过程的 stdout 上;fork 除了信号量,还能够过程间通信;同步办法fork 没有同步办法,其余三个办法有同步办法。execSync 和 execFileSync 返回值 Buffer 就是子过程的输入后果。spawnSync 返回对象的 stdout Buffer 中是子过程的输入。

October 3, 2022 · 1 min · jiezi

关于node.js:用Nodejs-React和Socketio创建一个看板应用

本文为译文,原文地址为: Building a Kanban board with Node.js, React and Websockets 对于在这篇文章中,你能够学习如何构建一个看板利用,相似在JIRA, MonDay或者Trello等利用中看到那样。这个利用,将蕴含一个丑陋的drag-and-drop性能,应用的技术是React, Socket.io和DND(拖拽)技术。用户能够登录、创立并更新不同的工作,也能够增加评论。 Socket.ioSocket.io是一个风行的Javascript库,能够在浏览器和Node.js服务端之间创立实时的、双向的通信。它有着很高的性能,哪怕是解决大量的数据,也能做到牢靠、低延时。它恪守WebSocket协定,但提供更好的性能,比方容错为HTTP长连贯以及主动重连,这样能构建更为无效的实时利用。 开始创立创立我的项目根目录,蕴含两个子文件夹client和server mkdir todo-listcd todo-listmkdir client server进入client目录,并创立一个React我的项目。 cd clientnpx create-react-app ./装置Socket.is Client API和React Router.React Router帮咱们解决利用中的路由跳转问题。 npm install socket.io-client react-router-dom删除无用的代码,比方Logo之类的,并批改App.js为以下代码。 function App() { return ( <div> <p>Hello World!</p> </div> );}export default App;切换到server目录,并创立一个package.json文件。 cd server && npm init -y装置Express.js, CORS, Nodemon和Socket.io服务端API. Express.js是一个疾速、极简的Node.js框架。CORS能够用来处于跨域问题。Nodemon是一个Node.js开发者工具,当我的项目文件扭转时,它能主动重启Node Sever。 npm install express cors nodemon socket.io创立入口文件index.js touch index.js上面,用Express.js创立一个简略的Node服务。当你在浏览器中拜访http://localhost:4000/api时,上面的代码片断将返回一个JSON对象。 //index.jsconst express = require("express");const app = express();const PORT = 4000;app.use(express.urlencoded({ extended: true }));app.use(express.json());app.get("/api", (req, res) => { res.json({ message: "Hello world", });});app.listen(PORT, () => { console.log(`Server listening on ${PORT}`);});启动以上服务 ...

September 30, 2022 · 9 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()之后调用模块的属性或者办法了。 相干nodejs进阶视频解说:进入学习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里的模块 ...

September 28, 2022 · 3 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,能够在终端上显示出 √ 或 × 等的图标相干nodejs进阶视频解说进入学习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内容如下 ...

September 28, 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作为中间层的局部实际. 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代表着将两条数据聚合的自定义路由,如果须要聚合数据的需要比拟多,这块逻辑要独自封装到路由模块中治理,并且要写在代理转发的后面. ...

September 26, 2022 · 1 min · jiezi

关于node.js:彻底搞懂nodejs事件循环

nodejs是单线程执行的,同时它又是基于事件驱动的非阻塞IO编程模型。这就使得咱们不必期待异步操作后果返回,就能够持续往下执行代码。当异步事件触发之后,就会告诉主线程,主线程执行相应事件的回调。 以上是家喻户晓的内容。明天咱们从源码动手,剖析一下nodejs的事件循环机制。 nodejs架构首先,咱们先看下nodejs架构,下图所示: 如上图所示,nodejs自上而下分为 用户代码 ( js 代码 )用户代码即咱们编写的利用程序代码、npm包、nodejs内置的js模块等,咱们日常工作中的大部分工夫都是编写这个层面的代码。binding代码或者三方插件(js 或 C/C++ 代码)胶水代码,可能让js调用C/C++的代码。能够将其了解为一个桥,桥这头是js,桥那头是C/C++,通过这个桥能够让js调用C/C++。 在nodejs里,胶水代码的次要作用是把nodejs底层实现的C/C++库裸露给js环境。 三方插件是咱们本人实现的C/C++库,同时须要咱们本人实现胶水代码,将js和C/C++进行桥接。底层库nodejs的依赖库,包含赫赫有名的V8、libuv。 V8: 咱们都晓得,是google开发的一套高效javascript运行时,nodejs可能高效执行 js 代码的很大起因次要在它。 libuv:是用C语言实现的一套异步性能库,nodejs高效的异步编程模型很大水平上归功于libuv的实现,而libuv则是咱们明天重点要剖析的。 还有一些其余的依赖库 http-parser:负责解析http响应 openssl:加解密 c-ares:dns解析 npm:nodejs包管理器 ...对于nodejs不再过多介绍,大家能够自行查阅学习,接下来咱们重点要剖析的就是libuv。 nodejs进阶视频解说进入学习libuv 架构咱们晓得,nodejs实现异步机制的外围便是libuv,libuv承当着nodejs与文件、网络等异步工作的沟通桥梁,上面这张图让咱们对libuv有个大略的印象: 这是libuv官网的一张图,很显著,nodejs的网络I/O、文件I/O、DNS操作、还有一些用户代码都是在 libuv 工作的。既然谈到了异步,那么咱们首先演绎下nodejs里的异步事件:非I/O: 定时器(setTimeout,setInterval)microtask(promise)process.nextTicksetImmediateDNS.lookupI/O: 网络I/O文件I/O一些DNS操作...网络I/O对于网络I/O,各个平台的实现机制不一样,linux 是 epoll 模型,类 unix 是 kquene 、windows 下是高效的 IOCP 实现端口、SunOs 是 event ports,libuv 对这几种网络I/O模型进行了封装。 文件I/O、异步DNS操作libuv外部还保护着一个默认4个线程的线程池,这些线程负责执行文件I/O操作、DNS操作、用户异步代码。当 js 层传递给 libuv 一个操作工作时,libuv 会把这个工作加到队列中。之后分两种状况: 1、线程池中的线程都被占用的时候,队列中工作就要进行排队期待闲暇线程。2、线程池中有可用线程时,从队列中取出这个工作执行,执行结束后,线程偿还到线程池,期待下个工作。同时以事件的形式告诉event-loop,event-loop接管到事件执行该事件注册的回调函数。当然,如果感觉4个线程不够用,能够在nodejs启动时,设置环境变量UV_THREADPOOL_SIZE来调整,出于零碎性能思考,libuv 规定可设置线程数不能超过128个。nodejs源码先简要介绍下nodejs的启动过程:1、调用platformInit办法 ,初始化 nodejs 的运行环境。2、调用 performance_node_start 办法,对 nodejs 进行性能统计。3、openssl设置的判断。4、调用v8_platform.Initialize,初始化 libuv 线程池。5、调用 V8::Initialize,初始化 V8 环境。6、创立一个nodejs运行实例。7、启动上一步创立好的实例。8、开始执行js文件,同步代码执行结束后,进入事件循环。9、在没有任何可监听的事件时,销毁 nodejs 实例,程序执行结束。以上就是 nodejs 执行一个js文件的全过程。接下来着重介绍第八个步骤,事件循环。 ...

September 26, 2022 · 3 min · jiezi

关于node.js:对-Nodejs-事件驱动模型的深入理解

本文次要探讨以下问题: 1.Node.js 的事件驱动模型剖析 2.Node.js 如何解决高并发申请? 3.Node.js 的毛病介绍 先简略介绍一下 Node.js,Node.js 是基于事件驱动、非阻塞 I/O 模型的服务器端 JavaScript 运行环境,是基于 Google 的 V8 引擎在服务器端运行的单线程、高性能的 JavaScript 语言。 一、Node.js 事件驱动模型剖析 看懂上图之后,你就明确 Node.js 的事件驱动模型了,从上图中咱们能够看到以下几个局部: Application 应用层,也就是 JavaScript 交互层,是 Node.js 的罕用模块,比方 http,fs 等。 V8 是 V8 引擎层,次要用于解析 JavaScript,与应用层和 NodeApi 层交互。 NodeApi 为下层模块提供零碎调用,并与操作系统交互。 Libuv 是一个跨平台的底层包,实现了线程池、事件循环、文件操作等。实现异步是 Node.js 的外围。 Libuv 层保护一个事件队列的事件队列。当申请到来时,Node.js 的应用层和 NodeApi 层将申请作为事件放入事件队列,设置回调事件函数,而后持续承受新的申请。 在 Libuv 层的 Event Loop 事件循环中,事件队列中的事件被间断读取。在读取事件的过程中,如果遇到非阻塞事件,就本人解决,解决完后调用回调函数将后果返回给下一层。对于阻塞事件,会委托给后盾线程池来解决。当这些阻塞操作实现后,执行后果将和提供的回调函数一起放入事件队列。当事件循环再次读取该事件时,将再次执行搁置在队列中的事件回调函数,最初将后果返回给下级。详情请参考下图: 二、Node.js 如何解决高并发申请?如果你了解了最初一个问题,就好了解了。如果要总结的话,就是异步无阻塞编程的思维。当遇到耗时的操作时,会以异步非阻塞的形式进入事件队列,不会影响后续申请的执行。循环将读取这个耗时的申请,并将其交给线程池进行解决。当这些耗时的操作被解决后,会再次进入事件队列,申请后果通过事件循环和回调返回给下层利用,最终返回给客户端。以上形式缩小了高并发的等待时间,让高并发能够从容应对。 三、Node.js 的毛病介绍通过下面的介绍,咱们晓得了 Node.js 的事件驱动模型,上面咱们将介绍 Node.js 的不足之处。 Node.js 最大的毛病是一次只能服务一个申请。目前大部分服务器都是多核 CPU,导致 CPU 利用率非常低,资源节约。 ...

September 23, 2022 · 1 min · jiezi

关于node.js:爆肝撸了个了个羊通关助手Vue-node版本

vue-sheep前言本我的项目应用 vue2 + nodejs实现羊了个羊疾速通关,仅为学习应用,请勿应用本程序歹意对游戏服务器继续造成压力,所有后果自负!!!t 参数蕴含个人信息,任何状况请勿透露 工具举荐:Fiddler/HTTPDebugger/Charles【PC】、HttpCarry【Android】、Stream【iphone】 github地址vue-sheep 个性反对在线填写抓包参数反对随机生成工夫和自定义工夫最大反对10次通关,能够依据本人需要更改,切勿滥用应用# 拷贝代码git clone https://github.com/hu-snail/vue-sheep.git# 进入我的项目cd vue-sheep# 装置依赖yarn # or npm i# 运行yarn serve预览截图

September 17, 2022 · 1 min · jiezi

关于node.js:跨语言调用C代码的新方式DllExport

在以前,如果有其余语言须要调用C#编写的库,那基本上只有通过各种RPC的形式(HTTP、GRPC)或者引入一层C++代理层的形式来调用。 自从微软开始踊跃开发和钻研Native AOT当前,咱们有了新的形式。那就是间接应用Native AOT函数导出的形式,其它语言(C++、Go、Java各种反对调用导出函数的语言)就能够间接调用C#导出的函数来应用C#库。 废话不多说,让咱们开始尝试。开始尝试 咱们先来一个简略的尝试,就是应用C#编写一个用于对两个整数求和的Add办法,而后应用C语言调用它。 1.首先咱们须要创立一个新的类库我的项目。这个大家都会了,能够间接应用命令行新建,也能够通过VS等IDE工具新建。https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...https://weibo.com/a/hot/76273...

September 16, 2022 · 1 min · jiezi

关于node.js:Nodejs工程师养成计划含源码ppt

download:Node.js工程师养成打算含源码pptJava中使用比较器解决按照特定的字符串次序排序List 引言明天工作需要中,有一个小需要,要按照某一个特定的次序排列一个List。 举例: 原始的List 中存在3个String 元素 原始List : python,Java,C++现在需要按照另一个次序排序 申请List:C++ ,python,Java。网上大部分的排序都是根据某一个值,比如int,long 等等进行比大小,很少能找到按照特定字符串的资料。传统的代码使用for循环等等也能解决这个问题,然而心愿使用比较器的形式解决这个问题,明天就浅浅地研究一下。 原理通过研究,最好的形式还是着眼于字符串的坐标值来解决这个问题,通过坐标值的比较来实现这个问题。 实践样例1 筹备实体类 /** @author fangzhou@date 2022/7/27 11:24 上午 */public class Right { private String rightId;public String getRightId() { return rightId;}public void setRightId(String rightId) { this.rightId = rightId;}}复制代码2 解决打算 public static void main(String[] args) { // rightListMe 原始申请的类 List<Right> rightListMe = new ArrayList<>(); Right right = new Right(); right.setRightId("rightId111"); Right right1 = new Right(); right1.setRightId("rightId222"); Right right2 = new Right(); right2.setRightId("rightId333"); rightListMe.add(right); rightListMe.add(right1); rightListMe.add(right2); // rightListHe 特定次序的类 List rightListHe = new ArrayList<>(); rightListHe.add("rightId333"); rightListHe.add("rightId111"); rightListHe.add("rightId222"); // 核心比较器,通过该indexOf 找到下标 Collections.sort(rightListMe, new Comparator() { @Override public int compare(Right o1, Right o2) { int index1 = rightListHe.indexOf(o1.getRightId()); int index2 = rightListHe.indexOf(o2.getRightId()); return (index1 == -1 || index2 == -1) ? (index2 - index1) : (index1 - index2); } }); for (Right s : rightListMe) { System.out.println(s.getRightId()); }复制代码3 输入后果 ...

September 14, 2022 · 1 min · jiezi

关于node.js:记一次个人开发者如何让H5婚礼请帖在微信里体面的流转

我的公众号原文地址 ⚠️ 很要害的前提 ⚠️ ❗️集体开发者应用wx-jssdk的权限受限❗️(无转发给好友、分享朋友圈等权限),可先去「设置与开发-接口权限」查看权限详情。♂️文末是我说的「体面」❗️公众号设置 服务端代码(基于Koa2开发,省略服务器搭建代码,仅提供关键步骤代码)1.编写「服务器配置-服务器地址(URL)」所须要的接口地址https://yourserver.com/api/ch...let sha1 = require("sha1");/** * 微信公众号-指定服务器地址-验证接口 * @param {*} ctx */checkToken: async (ctx) => { const { signature, timestamp, nonce, echostr } = ctx.query; //ctx.query获取申请中携带的参数 let { token } = wxconfig; //将Token,timestamp,nonce按字典排序,排序后链接成一个字符串 let str = [token, timestamp, nonce].sort().join(""); //应用sha1模块进行sha1加密 let sha1Str = sha1(str); //判断加密后的字符串与申请中signature是否相等 if (sha1Str === signature) { ctx.body = echostr; } else { ctx.body = "Token check failed."; }};这一步OK之后,在「微信公众号后盾就能胜利开启服务器了」。接下来就是编写H5在微信里调用wx-jssdk相干性能所须要的受权过程。其实次要就是拿到wxconfig所须要的一些必要参数。 编写wx.config所需数据的接口https://yourserver.com/api/wx...需受权网站的url生成wxconfig数据的大抵流程:获取access_token,通过access_token获取jsapi_ticket;而后拼接access_token、jsapi_ticket、noncestr、timestamp、要受权的页面的url生成签名signature,最终将appId、timestamp、nonceStr、signature返回给前端,前端调用wx.config进行注册,胜利后就能够在wx.ready中调用相干js接口了。 wxConfig.js文件代码!!!这里局部代码借鉴来的,懒得改了大抵流程都是这样!const sha1 = require("sha1");const request = require("request");const { wxconfig } = require("./wxConfig");// 为了应答缓存压力,不要每次刷新token,访问量高会带来很大问题// 因为获取access_token的接口,一天最多调用2000次,每次有效期是两个小时let CACHE = { ticket: "", ticketTimeout: 0, //ticket过期工夫 ticketTime: 0, //获取ticket工夫 accessToken: "", accessTokenTimeout: 0, //token过期工夫 accessTokenTime: 0, //获取token工夫};class wxModel { /** * 刷新access_token */ static async refreshAccessToken() { return new Promise((resolve, reject) => { const tokenUrl = `${wxconfig.getAccessTokenUrl}?grant_type=client_credential&appid=${wxconfig.appId}&secret=${wxconfig.appSecret}`; request(tokenUrl, (error, response, body) => { if (typeof body === "string") { try { body = JSON.parse(body); } catch (e) { body = { errcode: "-1000", body, }; } } if (body && (!body.errcode || body.errcode == 0)) { CACHE.accessToken = body.access_token; CACHE.accessTokenTimeout = body.expires_in * 500; CACHE.accessTokenTime = new Date(); resolve(CACHE.accessToken); } else if (body) { reject(body.errmsg); } else { reject("未知异样"); } }); }); } /** * 刷新ticket * @param {*} access_token * @param {*} callback */ static async refreshJsapiTicket(access_token) { // Jsapi_ticket return new Promise((resolve, reject) => { let ticketUrl = `${wxconfig.getJsapiTicketUrl}?access_token=${access_token}&type=jsapi`; request(ticketUrl, function (err, response, content) { content = JSON.parse(content); if (content && (content.errcode == 0 || !content.errcode)) { CACHE.ticket = content.ticket; CACHE.ticketTimeout = content.expires_in * 500; CACHE.accessTokenTime = new Date(); resolve(CACHE.ticket); // ticket } else if (content) { reject(content.errmsg); } else { reject("未知异样"); } }); }); } /** * 获取wxconfig * @param {*} url * @returns */ static async geneWxConfig(url) { // 获取access_token let access_token = CACHE.accessToken; let ticket = CACHE.ticket; if ( !access_token || new Date() - CACHE.accessTokenTime > CACHE.accessTokenTimeout ) { access_token = await this.refreshAccessToken(); ticket = await this.refreshJsapiTicket(access_token); } let nonceStr = this.createNonceStr(); let timestamp = this.createTimestamp(); let signature = this.createSign({ jsapi_ticket: ticket, nonceStr, timestamp, url, }); return { appId: wxconfig.appId, access_token, ticket, timestamp, nonceStr, signature, }; } /** * 随机字符串 */ static createNonceStr() { return Math.random().toString(36).substr(2, 15); } /** * 工夫戳 */ static createTimestamp() { return parseInt(new Date().getTime() / 1000).toString(); } /** * 生成签名 * ⚠️ 只对url#后面局部加密 * ⚠️ noncestr全副小写 * @param {*} config */ static createSign(config) { let ret = { jsapi_ticket: config.jsapi_ticket, nonceStr: config.nonceStr, timestamp: config.timestamp, url: config.url, }; let url = ret.url.split("#")[0]; let string = `jsapi_ticket=${ret.jsapi_ticket}&noncestr=${ret.nonceStr}&timestamp=${ret.timestamp}&url=${url}`; let shaObjs = sha1(string); return shaObjs; }}module.exports = wxModel;wxConfig.js文件内容const wxconfig = { appId: "wx9xxxxxxx", appSecret: "xxxxxxxxxxxxxxxxxxxxx", token: "hxxxt", //公众号后盾自行配置的token getAccessTokenUrl: "https://api.weixin.qq.com/cgi-bin/token", getJsapiTicketUrl: "https://api.weixin.qq.com/cgi-bin/ticket/getticket",};module.exports = { wxconfig,};前端代码1.引入wx-jssdklet jssdkUri = `${window.location.protocol}//res.wx.qq.com/open/js/jweixin-1.6.0.js`;loadJs() { return new Promise((resolve, reject) => { if (window.wx) { return resolve(window.wx); } let script = document.createElement("script"); script.type = "text/javascript"; script.src = this.jssdkUri; window.document.getElementsByTagName("head")[0].appendChild(script); script.onload = () => { resolve(window.wx); }; script.onerror = reject; });}2.申请 /api/wxconfig 接口,拿到必要数据后调用 wx.configlet url = window.location.href;let data = await this.getWxconfig(url);wx.config({ debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert进去,若要查看传入的参数,能够在pc端关上,参数信息会通过log打出,仅在pc端时才会打印。 appId: data.appId, // 必填,公众号的惟一标识 timestamp: data.timestamp, // 必填,生成签名的工夫戳 nonceStr: data.nonceStr, // 必填,生成签名的随机串 signature: data.signature, // 必填,签名 jsApiList: [ "hideMenuItems", "updateAppMessageShareData", "updateTimelineShareData", ], // 必填,须要应用的JS接口列表});3.在wx.ready中编写「分享、转发」和其它业务须要的办法share({ title, desc, link, imgUrl }) { this.shareData = { title, desc, link, imgUrl }; if (!this.isReady) { console.error("wx jssdk is not ready."); return; } wx.ready(() => { wx.updateAppMessageShareData({ title, desc, link, imgUrl, // 分享图标 success: (res) => {}, fail: (err) => this.onError(err), }); wx.updateTimelineShareData({ title, link, imgUrl, // 分享图标 success: (res) => {}, fail: (err) => this.onError(err), }); });}hideMenu() { if (!this.isReady) { console.error("wx jssdk is not ready."); return; } wx.ready(() => { wx.hideMenuItems({ menuList: [ "menuItem:share:appMessage", "menuItem:share:timeline", "menuItem:share:qq", "menuItem:share:weiboApp", "menuItem:share:QZone", "menuItem:copyUrl", ], }); });}如何让H5在微信里活的「体面」!最初想说一下,作为一个集体开发者无奈调用wx.updateAppMessageShareData和wx.updateTimelineShareData等一些接口,我是怎么利用无限的性能让我的H5网页尽量「体面」的吧! ...

September 13, 2022 · 3 min · jiezi

关于node.js:Nodejs工程师养成计划某课含源码ppt

download:Node.js工程师养成打算某课含源码ppt编程猿自学it java python go c基于springboot的国际化解决方案1底漆1.1国际化概述作为一名服务器端开发人员,这里我想从本人的角度简略概述一下国际化(国际化也叫i18n,因为I和N之间有18个字母)是做什么的: 在理论的国际化我的项目中,责任是让服务器依据客户指定的语言,返回相应语言的内容。 1.2 spring/spring boot我的项目中国际化游戏性概述在spring/springboot的世界中,国内游戏基于以下界面:org . spring framework . context . message source .该接口次要定义了以下三种办法:公共接口音讯源{//如果国际化配置文件中找不到var1对应的音讯,能够给它一个默认值var3。@NullableString getMessage(String var1,@Nullable Object[] var2,@Nullable String var3,Locale var 4);//如果在国际化配置文件中找不到var1对应的音讯,抛出异样String getMessage(String var1,@Nullable Object[] var2,Locale var3)抛出NoSuchMessageException//这个办法临时没有做太多的钻研,所以本文也不会波及。string getMessage(MessageSourceResolvable var 1,Locale var2)抛出NoSuchMessageException}复制代码该接口的三个重要实现类如下: ResourceBundleMessageSourceReloadableResourceBundleMessageSource动态音讯源 2如何播放ResourceBundleMessage源(默认)首先咱们来看看springboot我的项目中国际化最根本的玩法: (1)构建springboot我的项目(至多增加web依赖)。Messages.properties(默认配置) 用户名=溜溜球复制代码 messages_en_US .属性 user.name=yoyo-ENuser.name1=nrscuser.name2=nrsc{0}-{1}复制代码 音讯_zh_CN.properties 用户名1=张耳User.name2=张耳{0}-{1}复制代码(3)创立一个控制器测试类@RestController公共类i18d专制控制器{@主动连线公有MessageSource messageSource @GetMapping("/hello ")公共字符串hello() {String defaultM = messageSource。getMessage("user.name ",null,locale context holder . getlocale());字符串message1 =音讯源。getMessage("user.name1 ",null,locale context holder . getlocale());字符串message2 = messageSource。getMessage("user.name2 ",new String[]{"WW "," MM"},locale context holder . getlocale());字符串message3 = messageSource。getMessage("user.nameXX ",null," defaultName ",locale context holder . getlocale()); ...

September 12, 2022 · 3 min · jiezi

关于node.js:听Node服务线上故障分享的思考

有任何问题都能够留言征询。 思考1写入量很大,导致redis的rdb长久化异样 一开始排查到问题,是拜访Redis返回时长较长。 而后看到应用服务的报错信息: MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error. 再查看redis组件的日志: can't save in background: fork: cannot allocate memory 阐明是bgsave出错了,无奈申请到内存。 思考文章不易,请关注公众号 毛毛虫的小小蜡笔,多多反对,谢谢。 1、bgsave vs savesave间接调用rdbSave函数,阻塞redis主过程,直到保留实现为止。在主过程阻塞期间,服务器不能解决客户端的任何申请。 如果数据量小,用此命令可能感觉不出有什么区别,然而当数据量很大的时候,就须要审慎应用这个命令。 bgsave命令执行之后立刻返回OK ,而后redis fork出一个新子过程,原来的redis 过程(父过程)持续解决客户端申请,而子过程则负责将数据保留到磁盘,而后退出。 2、rdb的毛病1、如果您须要在 Redis 进行工作时(例如断电后)将数据失落的可能性降到最低,那么 RDB 并不好。您能够配置生成 RDB 的不同保留点(例如,在对数据集至多 5 分钟和 100 次写入之后,您能够有多个保留点)。然而,您通常会每五分钟或更长时间创立一个 RDB 快照,因而,如果 Redis 因为任何起因在没有正确敞开的状况下进行工作,您应该筹备好失落最新分钟的数据。 ...

September 9, 2022 · 1 min · jiezi

关于node.js:会计老婆大人的前端小跟班儿node-操作-Excel-表格

前言我女朋友,是个会计, 她每天都要拾掇两样货色,表格和我!通常状况下,她拾掇不了表格,情绪就会变差,随后就会拾掇我!按逻辑,表格就是我被拾掇的罪魁祸首,那如果我搞定了表格······岂不是·······嘻嘻嘻 一个机会的呈现"这里有几个表格, 你给我把几个表格外面的内容放在一个文件外面" 此时, 我曾经意识到了, 她最近情绪不好, 然而我又体现的比拟好, 她没什么机会骂我 我晓得, 这只是一个借口, 我肯定不能让她未遂, 还好我有 "技术" O(∩_∩)O~接下来, 我就开始了我的操作.PS : 明天肯定不能挨骂 筹备工作文件夹a.xlsx : 有两个表格页b.xlsx : 有一个表格页 指标 把两个 Excel 表格合并成一个读取两个 Excel 表格的内容, 合并成一个, 写入到一个新的 Excel 表格内 开始搞下载第三方 $ npm install node-xlsx // 导入第三方const xlsx = require('node-xlsx')// 开始读取 excel 文件// 测试读取 a.xlsx 文件const workbook = xlsx.parse('./a.xlsx')console.log(workbook)接下来去命令行运行一下这个文件试试看 $ node index.js 失去的后果是 [ { name: '第一页', data: [ [Array], [Array] ] }, { name: '第二页', data: [ [Array], [Array] ] }]咱们发现, 把第一个 excel 表格的所有内容都读取进去了 ...

September 8, 2022 · 2 min · jiezi

关于node.js:inquirer命令行交互原理三inquirer源码实现流程

目录inquirer命令行交互原理?(一)readline的实现办法和原理inquirer命令行交互原理?(二)手写readline实现inquirer命令行交互原理?(三)inquirer源码实现流程 补充知识点前两篇文章曾经具体的介绍了inquirer的相干知识点,上面是inquirer源码中用到的库的简要介绍ansi-escapes ANSI_escape_code 翻译:ANSI转义序列是用于在视频文本终端和终端模拟器上管制光标地位、色彩、字体款式和其余选项的带内信令的规范。某些字节序列(大多数以ASCII转义字符和方括号字符开始)嵌入到文本中。终端将这些序列解释为命令,而不是逐字显示的文本。 ANSI序列在20世纪70年代被引入,以取代特定供应商的序列,并在20世纪80年代初在计算机设备市场上宽泛应用。它们被用于开发、迷信、商业文本利用以及公告牌零碎,以提供标准化的性能。 只管硬件文本终端在21世纪变得越来越少见,但ANSI规范的相关性依然存在,因为绝大多数终端模拟器和命令控制台至多解释了ANSI规范的一部分。 rxjsrxjs inquirer实现原理inquirer最外围的就是readline;

September 4, 2022 · 1 min · jiezi

关于node.js:关于es-cjs-umd-iife-相关介绍

目前在用vite构建我的项目工具库发现一些常识盲区ESECMAScript Module,当初应用的模块计划,应用 import export 来治理依赖浏览器间接通过 <script type="module"> 即可应用该写法。NodeJS 能够通过应用 mjs 后缀或者在 package.json 增加 "type": "module" 来应用 import pmutils from '../../lib/pm-utils.es.js' // 测试在es模式 node.js中环境console.log(pmutils) 不反对 在package.json中增加 { "type": "module" }编译通过 cjsCommonJS,只能在 NodeJS 上运行,应用 require("module") 读取并加载模块 每个文件就是一个模块,有本人的作用域。在一个文件外面定义的变量、函数、类,都是公有的,对其余文件不可见 umd同时兼容 CJS 和 AMD,并且反对间接在前端用 <script src="lib.umd.js"></script> 的形式加载 AMD,全称是Asynchronous Module Definition,即异步模块加载机制iife因为咱们的应用程序可能蕴含来自不同源文件的许多函数和全局变量,所以限度全局变量的数量很重要。如果咱们有一些不须要再次应用的启动代码,咱们能够应用 IIFE 模式。因为咱们不会再次重用代码,因而在这种状况下应用 IIFE 比应用函数申明或函数表达式更好 const makeWithdraw = (balance) => ((copyBalance) => { let balance = copyBalance; // This variable is private const doBadThings = () => { console.log('I will do bad things with your money'); }; doBadThings(); return { withdraw(amount) { if (balance >= amount) { balance -= amount; return balance; } return 'Insufficient money'; }, };})(balance);const firstAccount = makeWithdraw(100); // "I will do bad things with your money"console.log(firstAccount.balance); // undefinedconsole.log(firstAccount.withdraw(20)); // 80console.log(firstAccount.withdraw(30)); // 50console.log(firstAccount.doBadThings); // undefined; this method is privateconst secondAccount = makeWithdraw(20); // "I will do bad things with your money"console.log(secondAccount.withdraw(30)); // "Insufficient money"console.log(secondAccount.withdraw(20)); // 0

September 3, 2022 · 1 min · jiezi

关于node.js:某课网Nodejs工程师养成计划分xiang

download:Node.js工程师养成打算云盘无密需要对于须要前端实现无痛刷新Token,无非就两种: 申请前判断Token是否过期,过期则刷新申请后依据返回状态判断是否过期,过期则刷新 解决逻辑实现起来也没多大差异,只是判断的地位不一样,外围原理都一样: 判断Token是否过期 没过期则失常解决过期则发动刷新Token的申请 拿到新的Token保留从新发送Token过期这段时间内发动的申请 重点: 放弃Token过期这段时间发动申请状态(不能进入失败回调)把刷新Token后从新发送申请的响应数据返回到对应的调用者 实现 创立一个flag isRefreshing 来判断是否刷新中创立一个数组队列retryRequests来保留须要从新发动的申请判断到Token过期 isRefreshing = false 的状况下 发动刷新Token的申请 刷新Token后遍历执行队列retryRequests isRefreshing = true 示意正在刷新Token,返回一个Pending状态的Promise,并把申请信息保留到队列retryRequests中 import axios from "axios";import Store from "@/store";import Router from "@/router";import { Message } from "element-ui";import UserUtil from "@/utils/user"; // 创立实例const Instance = axios.create();Instance.defaults.baseURL = "/api";Instance.defaults.headers.post["Content-Type"] = "application/json";Instance.defaults.headers.post["Accept"] = "application/json"; // 定义一个flag 判断是否刷新Token中let isRefreshing = false;// 保留须要从新发动申请的队列let retryRequests = []; // 申请拦挡Instance.interceptors.request.use(async function(config) { Store.commit("startLoading"); const userInfo = UserUtil.getLocalInfo(); if (userInfo) { ...

September 3, 2022 · 2 min · jiezi

关于node.js:Nodejs工程师养成计划完毕

download:Node.js工程师养成打算结束Spring5源码5-Bean生命周期后置处理器 次要阐明三种生命周期增强器: BeanFactoryPostProcessor:BeanFactory 后置处理器 BeanDefinitionRegistryPostProcessor:bean定义注册后置处理器BeanFactoryPostProcessorBeanPostProcessor:Bean后置处理器 BeanPostProcessorMergedBeanDefinitionPostProcessorSmartInstantiationAwareBeanPostProcessorInstantiationAwareBeanPostProcessorInitializingBean DisposableBean (销毁的计划咱们临时不做阐明) 1.1 什么是 BeanPostProcessorBeanPostProcessor 是 Spring提供给咱们的一个十分重要的扩大接口,并且Spring外部的很多性能也是通过 BeanPostProcessor 来实现的(目前看到最典型的就是 AnnotationAwareAspectJAutoProxyCreator 的 注入)。 1.2 BeanPostProcessor 的品种BeanPostProcessor 在Spring 中的子类十分多(idea 显是有46个),比方 InstantiationAwareBeanPostProcessorAdapter : 在Spring 的bean加载过程中起了十分重要的作用AnnotationAwareAspectJAutoProxyCreator : bean 创立过程中的 属性注入时起作用AspectJAwareAdvisorAutoProxyCreator : Aspect 的 AOP 性能实现也全凭仗BeanPostProcessor 的个性。1.3 创立机会BeanFactoryPostProcessor:在 Spring 启动时对BeanDefinition 的创立 进行干涉解决。 BeanPostProcessor:一是Bean对应的BeanDefinition 的创立。二是Bean 实例的创立。因为在 Spring容器中,Bean的创立并非仅仅通过反射创立就完结了,在创立过程中,须要思考到Bean针对Spring容器中的一些属性,所以BeanDefinition 中不仅仅蕴含了 Bean Class 文件信息,还蕴含了 以后Bean在Spring容器中的一些属性,比方在容器中的作用域、是否懒加载、别名等信息。当Bean 进行实例化创立时须要依赖于对应的BeanDefinition 提供对应的信息。。 而因为 BeanPostProcessor 是参加了 Bean 创立过程。所以其创立肯定在一般 Bean 之前。实际上 BeanPostProcessor 的创立时在 Spring 启动时容器刷新的时候。 BeanPostProcessor 的 BeanDefinition 创立机会和一般 Bean没有区别,都是在Spring 启动时的BeanFactoryPostProcessor 中实现(确切的说是 ConfigurationClassPostProcessor 中实现)。 ...

September 3, 2022 · 15 min · jiezi

关于node.js:使用-Nodejs-Stream-API-减少服务器端内存消耗的一个具体例子

让咱们看一个示例,展现在内存耗费方面,采纳流的编程思路带来的微小优越性。 咱们先创立一个大文件: const fs = require('fs');const file = fs.createWriteStream('./big.file');for(let i=0; i<= 1e6; i++) { file.write('this is a big file.\n');}file.end();fs 模块可用于应用流接口读取和写入文件。 在下面的示例中,咱们通过一个循环写入 100 万行的可写流,向该 big.file 写入数据。 运行下面的代码会生成一个大概 400 MB 的文件。 这是一个简略的 Node Web 服务器,旨在专门为 big.file 提供服务: const fs = require('fs');const server = require('http').createServer();server.on('request', (req, res) => { fs.readFile('./big.file', (err, data) => { if (err) throw err; res.end(data); });});server.listen(8000);启动该服务器,其耗费的初始内存为 8 MB 左右。 应用浏览器拜访服务器之后,内存耗费跃升至 434.8 MB。 咱们基本上将整个 big.file 内容放在内存中,而后再将其写入响应对象。 这是十分低效的。 HTTP 响应对象(下面代码中的 res)也是一个可写流。 这意味着如果咱们有一个示意 big.file 内容的可读流,咱们能够将这两个相互连接起来,并在不耗费约 400 MB 内存的状况下取得简直雷同的后果。 ...

September 2, 2022 · 1 min · jiezi

关于node.js:Nodejs-应用高-CPU-占用率的分析方法

咱们在本地运行 Node.js 利用,应用 --inspect 标记启动应用程序,再次执行负载测试,在 Chrome 浏览器中关上 chrome://inspect: 单击利用下方的 inspect 按钮,而后开始 CPU 占用率剖析: 期待一段时间后,就能看到 CPU profile 的后果: 如何采集生产零碎上的 Node.js 利用性能数据呢? 在大多数状况下,如果性能问题只能在生产零碎重现,那么这种问题剖析起来的确很辣手,因为咱们须要雷同的环境配置、雷同的数据库、缓存等数据。 性能问题可能只针对某些类别的用户,因为他们有特定的数据。 在生产环境开启调试模式?这不是一个好的抉择,因为在调试模式下 Node.js 过程会耗费更多资源,而且不平安。 然而有一个更好的办法,应用查看器模块 https://nodejs.org/api/inspec... 按需获取配置文件。 它是一个 Node.js 内置模块,开发人员不用装置任何额定的依赖项,但倡议应用 inspector-api . 它是一个带有 Promise 反对的简略包装器。 让咱们创立一个记录 CPU 配置文件的端点。 上面是为 NestJS 创立一个示例,对于其余框架,它看起来十分类似: 代码如下: import { Controller, Post } from '@nestjs/common'import { promisify } from 'util'import Inspector from 'inspector-api'const profileRecordTime = 10000@Controller('/profile')export class ProfileController { @Post('/cpu') async cpu() { // don't wait till recording is finished setImmediate(async () => { // cpu profile will be saved in temp dir const inspector = new Inspector({ storage: { type: 'fs' } }) // enabling and starting profiling await inspector.profiler.enable() await inspector.profiler.start() // wait for 10 seconds and stop await promisify(setTimeout)(profileRecordTime) await inspector.profiler.stop() console.log('CPU profile has been written') await inspector.profiler.disable() }) return true }}所有代码都用 setImmediate 包裹,因为咱们不须要等到录制完结。 让咱们用 curl 测试一下: ...

September 2, 2022 · 2 min · jiezi

关于node.js:npm-install以及gyp等问题

排查pythonmac monterey有bug, 所以先解决下python, 增加上面两句 ln -s /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/bin/python3 /usr/local/bin/python3ln -s -f /usr/local/bin/python3 /usr/local/bin/pythonxcode装置并更新xcode以防万一 清理缓存npm clean --force

September 1, 2022 · 1 min · jiezi

关于node.js:Warning-Expected-server-HTML-to-contain-a-matchin

Warning: Expected server HTML to contain a matching <div> in <div>.在应用Next.js或者React.js进行SSR网站开发时,咱们常常会见到这种谬误,次要起因是因为SSR脱水和注水过程中发现元素渲染不统一。这种状况很可能是因为咱们应用代码执行环境进行了一些判断,咱们只须要将问题组件批改为客户端渲染(CRS)即可。目前我的组件Login呈现了问题,应用Next.js自带的dynamic引入来解决,React本人封装一个NoSSR即可。import dynamic from "next/dynamic";const LognIn = dynamic(import("./LogIn"), { ssr: false }); const User = () => { return ( &lt;&gt; &lt;LognIn/&gt;&lt;/&gt;);};export default User;

August 29, 2022 · 1 min · jiezi

关于node.js:RangeError-Array-buffer-allocation-failed

在应用 Node.js 合并文件分片时呈现了题目的错误信息。代码剖析m.merge = (opts) => { return new Promise((resolve, reject) => { const { filename, target } = opts; try { let len = 0; const bufferList = fs.readdirSync(`${STATIC_TEMPORARY}/${filename}`).map((hash, index) => { const buffer = fs.readFileSync(`${STATIC_TEMPORARY}/${filename}/${index}`); len += buffer.length; return buffer; }); // Merge files const buffer = Buffer.concat(bufferList, len); const ws = fs.createWriteStream(`${target}/${filename}`); ws.write(buffer); ws.close(); resolve({ success: true, msg: 'Section merge completed' }); } catch (error) { console.error(error); reject({ success: false, msg: error }); } });};const buffer = Buffer.concat(bufferList, len);定位到是上边这行呈现了问题,查看了一下服务器,node利用的内存占用是 192.1mb。 ...

August 29, 2022 · 1 min · jiezi

关于node.js:Nodejs获取Linux系统文件创建时间

最近在应用 Node.js 的 fs.readdir 遇到一个问题,就是想让读出的文件按创立工夫的先后排序。最初论断是,办不了!!!。上面记录一下钻研的过程。场景还原有上面这样一个网页利用,读取的是服务器上的文件,fs.readdir 读取到的文件列表是按 文件的批改工夫 排序的,并不是按创立工夫,如果你有强迫症,这个刚好戳中了你的“G”点。 如果咱们批改了第一个文件夹的名称,或者在它外部新增了文件,那么它就会跑到最初一个。(ps:然而我他么就想按最开始的顺序排列啊!!) 那么,咱们不能依照文件创建工夫排序吗? windows 与 linux 的文件创建工夫在windows零碎上,一个文件有3个工夫属性,他们别离是 创立工夫批改工夫拜访工夫 linux上的文件也有三个工夫属性,别离是 拜访工夫(access time 简写为 atime)批改工夫(modify time 简写为mtime)状态批改工夫(change time 简写为ctime) 很多人误将linux零碎上文件的ctime 对标成windows零碎上的创立工夫,这是不对的,ctime里的字母c是change的缩写而非create的缩写。当文件的元数据发生变化时,ctime就会产生扭转,比方文件的权限,拥有者,所属的组,硬链接,当然也包含文件内容发生变化。 所以,在linux零碎上,无奈取得文件的创立工夫了么?这是一个简单的问题,对于linux零碎上为什么不记录文件的创立工夫,有很多的探讨,有人认为文件的创立工夫对于大多数人来说是无用的,能够用其余来代替: 如果文件没有批改过,就等于mtime,即最初一次write工夫如果文件没有被批改权限过,就等于ctime,即最初一次应用chmod的工夫如果文件没有被读取过,就等于atime,即最初一个read的工夫 然而呢,总感觉有点鸡肋。 在 stackoverflow 上找到一个办法,本人把读取到的文件列表排序: return new Promise((resolve, reject) => { fs.readdir(dir, (err, items) => { if (err) return reject(err); const files = []; items.forEach((item) => { const info = fs.lstatSync(path.join(dir, item)); const h = m.encode(path.resolve(dir, item)); files.push({ name: item, extension: info.isDirectory() ? 'directory' : item.split('.').pop().toLowerCase(), hash: h, size: info.size, is_dir: info.isDirectory(), time: info.mtime.getTime() }); }); resolve({ success: true, data: { tree: files.sort((a, b) => a.time - b.time) }, });});惋惜它是依照文件的批改工夫排序的。 ...

August 28, 2022 · 1 min · jiezi

关于node.js:快到飞起的Bun会替代Node吗

背景这段时间一个性能号称能够吊打Node和Deno的JavaScript运行时Bun(包子)横空出世,立刻在JavaScript社区闹得满城风雨。那么到底这个号称快到飞起的包子运行时到底几斤几两呢?这篇文章就让咱们通过一些理论的例子来理解一下Bun提供的性能以及它比Node到底快了多少,最初再探讨一下Bun是不是能够代替Node。 什么是Bun咱们先来看官网形容: Bun is a fast all-in-one JavaScript runtime Bundle, transpile, install and run JavaScript & TypeScript projects — all in Bun. Bun is a new JavaScript runtime with a native bundler, transpiler, task runner and npm client built-in. 简略来说Bun是一个大而全的JavaScript运行时。 它不止做了Node和Deno的工作(JavaScript运行时),而且还原生反对上面这些性能: bundler: Bun能够像Webpack等工具一样对咱们的我的项目进行打包transpiler: 反对TypeScript/JavaScript/JSX的Transpiling,换句话来说就是你能够在我的项目外面间接写TypeScript和JSX语法而不必放心配错环境了task runner: 能够跑package.json外面的script脚本,相似于npm run xxx内置的和npm一样的包管理工具: 实现了和npm,yarn和pnpm等包管理工具一样的性能,不过更快有同学看到这里能够会问:这些性能不是当初前端和node生态都反对了吗?有什么好学的?其实不然,Bun的特色其实不在这些性能,而是在原生和快这两个方面。原生就意味着这是Bun自带的,咱们不须要写任何配置文件或者装置任何插件就能够用,这就升高了咱们编写代码的老本以及编写效率。而Bun另外一个特点是快,那它有如许快呢?看一些官网的形容: 从下面的形容能够看出这些数据: Bun的服务端渲染速度大略是Node的3倍Bun跑脚本的速度大略是npm run的30倍Bun的下载包的速度是yarn的20倍听起来的确有点快,到底实际效果如何呢?接着就让咱们理论看一下。 Bun性能介绍这部分内容将会介绍Bun和Node或者Node生态其余工具如npm的比照,而不会波及到Deno,因为Deno其实和Node的性能没有太大的区别。 Bundler和Transpiler作为一个前端工程师,咱们常常须要应用Webpack等工具来对咱们的代码进行transpile和bundle。和Node不同的是,Bun原生就反对了Bundler和Transipler这些能力,而不必咱们额定装置其它依赖。除了这些,Bun还内置了React脚手架的性能,你输出一个命令即可创立一个React利用: bun create react ./react-app下面的命令跑完后会生成一个这样目录构造的我的项目代码: react-app├── node_modules├── README.md├── bun.lockb├── node_modules.bun├── package.json├── public│ ├── favicon.ico│ ├── index.html│ ├── logo192.png│ ├── logo512.png│ ├── manifest.json│ └── robots.txt└── src ├── App.css ├── App.jsx ├── images.d.ts ├── index.css ├── index.jsx ├── logo.svg └── reportWebVitals.js从下面的目录构造来看,应用bun创立的React利用非常清新,根本没有额定的配置文件,能够间接进行代码的编写。最重要的是,在笔者的渣渣电脑上跑这个命令只须要6.55s!。而相比之下应用npx create-react-app跑了足足四分钟才创立出一个React我的项目来。换句话来说Bun创立一个React我的项目的速度是用npm通过create-react-app创立速度的40倍!单纯从这个速度上看,Bun说本人快如闪电真的有余不为过。 ...

August 23, 2022 · 3 min · jiezi

关于node.js:Node-js-开发入门-UDP-编程小白也能轻松学会

UDP 协定UDP 协定(无连贯传输协定)是运行在运输层之上,可能为调用它的应用程序提供一种无需建设连贯就能够间接发送数据包的网络传输协定;它次要有以下两个特点: 无连贯: 不同于 TCP 在数据传输之前须要通过三次握手来建设连贯,UDP 无需做任何筹备即可进行数据传输操作,因而 UDP 的数据传输不存在因连贯而导致的时延;TCP 须要在客户端与服务端之间保护连贯状态,以便实现 TCP 的牢靠数据传输服务,但因为 UDP 是无连贯的,因而 UDP 无需保护客户端与服务端之间的连贯状态。应用层领有相对控制权: UDP 会把应用层的数据包间接交给网络层,同样的在接管到网络层的数据包后间接交给应用层,UDP 不会对数据包做任何的操作;TCP 个别会通过拥塞管制来避免过多数据进入网络,从而导致网络阻塞,但 UDP 并不理睬这些问题,因而可能最大限度的独霸网络带宽。出于上述两个起因,应用 UDP 的利用领有对数据包、带宽的相对控制权。不过须要留神的是,即便 UDP 也应用了测验机制,也不意味着它对数据有效性进行任何保障,UDP 的测验仅用来查看数据包是否呈现了过错,即便呈现了过错,它还是会将数据包交给应用层,除了给予应用层一些敌对的正告外,它不会采取或提供任何补救措施。 绝对于 TCP,UDP 是一个绝对比较简单的运输层网络传输协定,也因为它的简便性,它领有 TCP 无法比拟的效率劣势,所以对于 DNS、语音视频流等对效率要求较高、对准确性要求较低的利用个别多应用 UDP 协定。 UDP 广(多)播咱们常见的 UDP 服务是一对一的单播服务,接下来咱们将探讨一对多的 UDP 服务: 播送:播送与单播的次要区别是指标 IP 地址的不同,单播的指标 IP 地址是具体的主机地址,而播送的指标 IP 地址是所属局域子网中的播送地址,即位于该局域子网下的所有主机均能收到一份数据正本;多播:也称为组播,是将网络中属于同一业务类型的主机进行逻辑上的分组,信息收发仅产生在同一分组中,不在该分组的的主机无奈收发对应的数据。因为播送简直会占用所属局域子网的所有带宽,且只能在局域网中应用,因而基于播送的利用绝对于多播来说,数量非常少,而多播的一些长处使得它十分实用于生产者/消费者模式下的网络应用: 同一分组下的主机共享同一通道,这大大节俭了服务器带宽;因为多播协定由数据消费者来确定是否进行数据的转发,所以对于生产者的服务端来说,其所需的带宽是固定的,与作为消费者的客户端的数量无关;多播不仅能够在局域网中应用,也可在广域网中应用。最初须要留神的是,无论是播送还是多播,它们仅仅进行数据的转发,而不关怀且无奈保障接收端可能正确地接管到数据,其个性完全符合 UDP 协定,因而播送、多播罕用于 UDP 协定。 利用先装置 dgram 模块 服务端项代码如下: /** * UDP服务端 *///载入udp模块const dgram = require("dgram");//创立服务器const server = dgram.createSocket("udp4"); server.on("message",(msg,rinfo)=>{ //将接管到的音讯返回客户端 var strmsg = "你好,UDP客户端,音讯曾经收到!"; server.send(strmsg,rinfo.port,rinfo.address); console.log("服务器接管到来自"+rinfo.address+":"+rinfo.port+" 的音讯:"+msg.toString());}); server.on("listening",()=>{ let adress = server.address(); console.log("服务器监听:",adress.adress+":"+adress.port);}); server.on("error",(err)=>{ console.err("服务器异样谬误:"+err.message);}); server.bind(8234,"127.0.0.1");客户端项代码如下: ...

August 22, 2022 · 2 min · jiezi

关于node.js:使用Nodejs打包下载文件

本文介绍一下应用Node.js的fs模块创立zip文件,须要借助 archiver 包。后端创立归档文件这个操作个别由前端发动,如下图所示: 把抉择中文件地址发送给后端,后端依据文件地址创立归档文件,最初把归档文件地址返回给前端实现下载。 // zip文件长期目录const ZIP_TEMPORARY = path.resolve(__dirname, '../../static/zip');/** * 文件归档 * @param opts 其中opts.targets就是所选文件的地址 type:Array */m.zip = (opts) => { return new Promise((resolve, reject) => { if (!opts.targets || opts.targets?.length === 0) { reject({ success: false, msg: '参数谬误' }); } const file_name = `/${new Date().getTime()}.zip`; const output = fs.createWriteStream(ZIP_TEMPORARY + file_name); const archive = archiver('zip', { zlib: { level: 9 }, // Sets the compression level. }); // 当所有文件都被打包实现会触发这个事件 output.on('close', () => { console.log(`${archive.pointer()} total bytes`); console.log('archiver has been finalized and the output file descriptor has closed.'); resolve({ success: true, hash: m.encode(ZIP_TEMPORARY + file_name), }); }); output.on('end', () => { console.log('Data has been drained'); }); // good practice to catch this error explicitly archive.on('error', (err) => { throw err; }); // 以管道的模式把文件输入到zip archive.pipe(output); // archive.directory 这个办法比拟重要,它的作用是把子文件夹的文件也全副打包 opts.targets.forEach(async (item) => { const info = fs.lstatSync(item); if (info.isDirectory()) { archive.directory(item, item.split('/').pop(), null); } else { archive.file(item, { name: item.split('/').pop() }); } }); archive.finalize().then(); });};这样程序执行后就能够在指定目录生成一个按工夫戳命名的.zip文件。 ...

August 20, 2022 · 1 min · jiezi

关于node.js:Nodejs工程师养成计划完结含文档源码

Node.js工程师养成打算完结含文档源码点击下载:网盘链接深入剖析Spring Boot 的SPI机制简介SPI(Service Provider Interface)是JDK内置的一种服务提供发现机制,可能用来启用框架扩大和替换组件,次要用于框架中开发,例如Dubbo、Spring、Common-Logging,JDBC等采纳采纳SPI机制,针对同一接口采纳不同的实现提供应不同的用户,从而提高了框架的扩展性。Java SPI实现Java内置的SPI通过java.util.ServiceLoader类解析classPath和jar包的META-INF/services/目录 下的以接口全限定名命名的文件,并加载该文件中指定的接口实现类,以此实现调用。示例说明创建动静接口public interface VedioSPI{ void call();} 复制代码实现类1public class Mp3Vedio implements VedioSPI{ @Overridepublic void call(){ System.out.println("this is mp3 call");}}复制代码实现类2public class Mp4Vedio implements VedioSPI{ @Overridepublic void call(){ System.out.println("this is mp4 call");}}复制代码在我的项目的source目录下新建META-INF/services/目录下,创建com.skywares.fw.juc.spi.VedioSPI文件。 相干测试public class VedioSPITest{ public static void main(String[] args){ ServiceLoader<VedioSPI> serviceLoader =ServiceLoader.load(VedioSPI.class); serviceLoader.forEach(t->{ t.call(); });}}复制代码说明:Java实现spi是通过ServiceLoader来查找服务提供的工具类。 源码分析上述只是通过简略的示例来实现下java的内置的SPI功能。其实现原理是ServiceLoader是Java内置的用于查找服务提供接口的工具类,通过调用load()方法实现对服务提供接口的查找,最初遍从来逐个拜访服务提供接口的实现类。从源码可能发现: ServiceLoader类本身实现了Iterable接口并实现了其中的iterator方法,iterator方法的实现中调用了LazyIterator这个外部类中的方法,解析完服务提供接口文件后最终后果放在了Iterator中返回,并不反对服务提供接口实现类的间接拜访。 所有服务提供接口的对应文件都是搁置在META-INF/services/目录下,final类型决定了PREFIX目录不可变更。 诚然java提供的SPI机制的思维非常好,然而也存在相应的弊病。具体如下: Java内置的方法形式只能通过遍从来获取服务提供接口必须放到META-INF/services/目录下。 针对java的spi存在的问题,Spring的SPI机制沿用的SPI的思维,但对其进行扩大和优化。Spring SPISpring SPI沿用了Java SPI的设计思维,Spring采纳的是spring.factories形式实现SPI机制,可能在不修改Spring源码的前提下,提供Spring框架的扩展性。Spring 示例定义接口public interface DataBaseSPI{ void getConnection();} 复制代码相干实现 DB2实现public class DB2DataBase implements DataBaseSPI{ @Overridepublic void getConnection(){ System.out.println("this database is db2");}} ...

August 18, 2022 · 1 min · jiezi

关于node.js:NodejsKoa2MySQL-打造前后端分离精品项目旧岛内附文档源码

Node.js+Koa2+MySQL 打造前后端拆散精品我的项目《旧岛》内附文档源码下载地址:百度网盘如果咱们做时光机回到 Go 1.18 以至一路追溯到 Go 1.4 版本,你会发现 atomic 包诚然提供了很多函数,但只有一个 Type,那就是 atomic.Value。这一节咱们回顾一下 atomic.Value 提供的能力。 A Value provides an atomic load and store of a consistently typed value. The zero value for a Value returns nil from Load. Once Store has been called, a Value must not be copied.A Value must not be copied after first use. 回顾一下咱们的此前的原子操作解读,所谓 atomic.Value 就是一个容器,可能被用来“原子地”存储和加载任意的值,并且是开箱即用的。使用场景atomic.Value 的两个经典使用场景: 周期性更新配置,并提供应多个协程 package main import ( "sync/atomic""time") func loadConfig() map[string]string { return make(map[string]string)} ...

August 18, 2022 · 2 min · jiezi

关于node.js:Nodejs仿知乎服务端深入理解RESTful-API内附文档源码

Node.js仿知乎服务端-深刻了解RESTful API内附文档源码下载地址:百度网盘Java 诊断工具 Arthas-实操案例实操案例排查函数调用异样通过curl 请求接口只能看到返回异样,然而看不到具体的请求参数和堆栈信息。shell@Alicloud:~$ curl{"timestamp":1655435063042,"status":500,"error":"Internal Server Error","exception":"java.lang.IllegalArgumentException","message":"id < 1","path":"/user/0"}复制代码查看UserController的 参数/异样在Arthas里执行:watch com.example.demo.arthas.user.UserController * '{params, throwExp}'复制代码 第一个参数是类名,反对通配第二个参数是函数名,反对通配 拜访watch命令会打印调用的参数和异样再次通过curl 调用可能在arthas外面查看到具体的异样信息。把获取到的后果开展,可能用-x参数:watch com.example.demo.arthas.user.UserController * '{params, throwExp}' -x 2复制代码返回值表达式在下面的例子里,第三个参数是返回值表达式,它实际上是一个ognl表达式,它反对一些内置对象: loaderclazzmethodtargetparamsreturnObjthrowExpisBeforeisThrowisReturn 比如返回一个数组:watch com.example.demo.arthas.user.UserController * '{params[0], target, returnObj}'复制代码条件表达式watch命令反对在第4个参数里写条件表达式,比如:当拜访 user/1 时,watch命令没有输入当拜访 user/101 时,watch会打印出后果。 当异样时捕捉watch命令反对-e选项,示意只捕捉抛出异样时的请求:watch com.example.demo.arthas.user.UserController * "{params[0],throwExp}" -e复制代码按照耗时进行过滤watch命令反对按请求耗时进行过滤,比如:watch com.example.demo.arthas.user.UserController * '{params, returnObj}' '#cost>200'复制代码热更新代码这个也是真的秀。 拜访 http://localhost:61000/user/0 ,会返回500异样:shell@Alicloud:~$ curl http://localhost:61000/user/0{"timestamp":1655436218020,"status":500,"error":"Internal Server Error","exception":"java.lang.IllegalArgumentException","message":"id < 1","path":"/user/0"}复制代码通过热更新代码,修改这个逻辑。jad反编译UserControllerjad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java复制代码jad反编译的后果保存在 /tmp/UserController.java文件里了。再打开一个Terminal 窗口,而后用vim来编辑/tmp/UserController.java:vim /tmp/UserController.java

August 16, 2022 · 1 min · jiezi

关于node.js:QCA9880-80211ac-Dual-band-QCA9880-2x2-3x3-24G5G

QCA9880 802.11ac Dual band QCA9880 2x2 2.4G/5G FCC/CE Qualcomm-Atheros QCA9880 chipset2.4GHz max 24dBm & 5GHz max 23dBm output powerIEEE 802.11ac compliant & backward compatible with 802.11a/b/g/n2×2 MIMO Technology, up to 867MbpsMini PCI Express edge connectorRoHS compliance ensure a high level protection of human health and the environment from risks that can be posed by chemicalsSupports Spatial Multiplexing, Cyclic-Delay Diversity (CDD), Low-Density Parity Check (LDPC) Codes, Maximal Ratio Combining (MRC), Space Time Block Code (STBC), Support the Frequency 4920MHz~4980MHz for US region.Supports IEEE 802.11d, e, h, i, k, r, v time stamp, and w standardsSupports Dynamic Frequency Selection (DFS)Cards are individually calibrated for Quality AssuranceDesigned for higher numbers of clients connections & support for extreme loadsLinux drivers support – Ath10k, Candela wireless drivers, QCA reference designApplications ...

August 15, 2022 · 2 min · jiezi

关于node.js:node中childprocess的回调执行流程的源码分析

回调打印后果正确的代码执行流程const cp = require('child_process');const path = require('path');const child = cp.exec('ls -al|grep node_modules', function(err, stdout,stderr){ console.log('start------------------'); console.log(err, stdout, stderr); console.log('end------------------');})child.stdout.on('data', (chunk) => { console.log('stdout data =', chunk);});child.stderr.on('data', (err) => { console.log('stderr data =', err );});child.stdin.on('close', ()=>{ console.log('stdin close');});child.stdout.on('close', () => { console.log('stdout close');});child.stderr.on('close', () => { console.log('stderr close');})child.on('exit',(exitCode) => { console.log('exit=', exitCode );})child.on('close',() => { console.log('close!');})代码执行的打印程序stdout data = drwxr-xr-x 280 chensi staff 8960 7 21 17:08 node_modulesexit= 0stdin closestderr closestart------------------null drwxr-xr-x 280 chensi staff 8960 7 21 17:08 node_modules end------------------close!stdout close谬误的代码执行流程将ls -al|grep node_modules这个命令批改为谬误的命令去执行,来察看回调的执行后果,ls3333333 -al|grep node_modulesconst child = cp.exec('ls3333333 -al|grep node_modules', function(err, stdout,stderr){ console.log('start------------------'); console.log(err, stdout, stderr); console.log('end------------------');})child.stdout.on('data', (chunk) => { console.log('stdout data =', chunk);});child.stderr.on('data', (err) => { console.log('stderr data =', err );});child.stdin.on('close', ()=>{ console.log('stdin close');});child.stdout.on('close', () => { console.log('stdout close');});child.stderr.on('close', () => { console.log('stderr close');})child.on('exit',(exitCode) => { console.log('exit=', exitCode );})child.on('close',() => { console.log('close!');})stderr data = /bin/sh: ls3333333: command not foundexit= 1stdin closestdout closestart------------------Error: Command failed: ls3333333 -al|grep node_modules/bin/sh: ls3333333: command not found at ChildProcess.exithandler (node:child_process:398:12) at ChildProcess.emit (node:events:539:35) at maybeClose (node:internal/child_process:1092:16) at Socket.<anonymous> (node:internal/child_process:451:11) at Socket.emit (node:events:539:35) at Pipe.<anonymous> (node:net:709:12) { code: 1, killed: false, signal: null, cmd: 'ls3333333 -al|grep node_modules'} /bin/sh: ls3333333: command not foundend------------------close!stderr close从打印后果能够看出,正确的输入后果和谬误的输入后果,在打印上还是存在差别,为此我钻研了源码,为了看上去不太干燥,我将尽可能的用通俗易懂的形式来进行形容,当然如果感觉还是看源码比拟清晰一点,也能够对照node源码来看,或者看我上两篇文章;我这里应用的是node v12版本;执行原理和目前的node版本没有差异;我手绘了一张回调函数的执行流程图;解答: ...

August 13, 2022 · 2 min · jiezi

关于node.js:Nodejs工程师养成计划某课完结内附资料文档

Node.js工程师养成打算【某课完结内附材料文档】下载地址:百度网盘从零开始自己动手写自旋锁咱们在写并发程序的时候,一个非常常见的需要就是保障在某一个时刻只有一个线程执行某段代码,像这种代码叫做临界区,而通常保障一个时刻只有一个线程执行临界区的代码的方法就是锁。在本篇文章当中咱们将会认真分析和学习自旋锁,所谓自旋锁就是通过while循环实现的,让拿到锁的线程进入临界区执行代码,让没有拿到锁的线程一直进行while死循环,这其实就是线程自己“旋”在while循环了,因而这种锁就叫做自旋锁。原子性在谈自旋锁之前就不得不谈原子性了。所谓原子性简略说来就是一个一个操作要么不做要么全做,全做的意义就是在操作的过程当中不能够被中断,比方说对变量data进行加一操作,有以下三个步骤: 将data从内存加载到寄存器。将data这个值加一。将失去的后果写回内存。 原子性就示意一个线程在进行加一操作的时候,不能够被其余线程中断,只有这个线程执行完这三个过程的时候其余线程才能够操作数据data。咱们现在用代码体验一下,在Java当中咱们可能使用AtomicInteger进行对整型数据的原子操作:import java.util.concurrent.atomic.AtomicInteger; public class AtomicDemo { public static void main(String[] args) throws InterruptedException { AtomicInteger data = new AtomicInteger();data.set(0); // 将数据初始化位0Thread t1 = new Thread(() -> { for (int i = 0; i < 100000; i++) { data.addAndGet(1); // 对数据 data 进行原子加1操作 }});Thread t2 = new Thread(() -> { for (int i = 0; i < 100000; i++) { data.addAndGet(1);// 对数据 data 进行原子加1操作 }});// 启动两个线程t1.start();t2.start();// 等待两个线程执行实现t1.join();t2.join();// 打印最终的后果System.out.println(data); // 200000}} ...

August 13, 2022 · 3 min · jiezi

关于node.js:node-管理子文件夹js文件执行

运行node服务,应用child_process管制子文件夹js文件执行 文件架构: index.js 主程序入口fileHelper.js 文件夹遍历readjson->main.js 子文件夹可执行文件入口package.json{ "name": "nodelearn", "version": "1.0.0", "description": "", "main": "src/index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC"}index.jsconst { spawn } = require("child_process");const readline = require("readline");const rl = readline.createInterface({ input: process.stdin, output: process.stdout });const { loopFileSync } = require("./fileHelper");const entryFileName = "main.js";const stratys = [];//待执行办法let aheadMessages = [];//通用执行//获取所有可执行文件const files = loopFileSync(__dirname);files.forEach(item => { const { fileName, fileDir, fileStat } = item; if (fileName === entryFileName) { let fileDirSplit = fileDir.split("\\"); if (fileDirSplit.length < 2) return; stratys.push([fileDirSplit[fileDirSplit.length - 2], fileDir, fileStat]); }})//进入用户抉择function execution(cb) { console.clear(); let showMessage = ""; aheadMessages = []; showMessage += "please select your choose.\n"; aheadMessages.push("0、exit\n"); aheadMessages.push("1、run lastest modify\n"); aheadMessages.push("2、run lastest create\n"); aheadMessages.push("3、run all\n"); showMessage += aheadMessages.join(""); stratys.forEach((item, index) => { showMessage += `${index + aheadMessages.length}、${item[0]}\n`; }) rl.question(showMessage, function (answer) { cb(answer, () => { rl.question("按回车键持续!", function () { execution(cb); }) }); })}function createNodeExecPromiseFactory(processName, jsFile) { return new Promise((resolve) => { let data = ''; let spawnObj = spawn("node ", [jsFile], { 'shell': true }); spawnObj.stdout.on("data", (chunk) => { data += chunk.toString(); }) spawnObj.on("exit", () => { console.log(`${new Date().toLocaleString()}-----开始执行工作:${processName}`); console.log(data); console.log(`${new Date().toLocaleString()}-----执行工作${processName}结束`); resolve(); }) })}function handleExecution(choose, next) { let chooseNum = Number(choose); if (isNaN(chooseNum) || chooseNum < 0 || chooseNum > (stratys.length + aheadMessages.length - 1)) { console.warn("抉择有误,请从新抉择!"); next(); return; } if (chooseNum == 0) { console.log("Exit!"); rl.close(); process.exit(0); } console.clear(); let newStratys = [], promises = []; switch (chooseNum) { case 1: //按批改工夫排序,执行最新批改 newStratys = stratys.slice().sort((a, b) => { return b[2].mtimeMs - a[2].mtimeMs; }) promises.push(createNodeExecPromiseFactory(newStratys[0][0], newStratys[0][1])); break; case 2: //按创立工夫排序,执行最新创立 newStratys = stratys.slice().sort((a, b) => { return b[2].ctimeMs - a[2].ctimeMs; }) promises.push(createNodeExecPromiseFactory(newStratys[0][0], newStratys[0][1])); break; case 3://执行全副工作 newStratys = stratys; for (let i = 0; i < newStratys.length; i++) { promises.push(createNodeExecPromiseFactory(newStratys[i][0], newStratys[i][1])); } break; default: newStratys = stratys; let _chooseNum = chooseNum - aheadMessages.length; promises.push(createNodeExecPromiseFactory(newStratys[_chooseNum][0], newStratys[_chooseNum][1])); break; } const p = Promise.all(promises); p.then(() => { console.log("执行所有工作结束!"); next(); })}execution(handleExecution);fileHelper.jsconst fs = require("fs");const path = require("path");function loopFile(filePath, cb) { fs.readdirSync(filePath, function (err, files) { if (err) { console.warn(err) } else { files.forEach(function (filename) { var filedir = path.join(filePath, filename); fs.stat(filedir, function (eror, stats) { if (eror) { console.warn('获取文件stats失败'); } else { var isFile = stats.isFile(); var isDir = stats.isDirectory(); if (isFile) { if (typeof cb === "function") cb(filename, filedir,fileStat); } if (isDir) { loopFile(filedir, cb); } } }) }); } });}function loopFileSync(filePath) { const result = []; function loop(filePath) { let files = fs.readdirSync(filePath); files.forEach(function (fileName) { let fileDir = path.join(filePath, fileName); let fileStat = fs.statSync(fileDir); if (fileStat.isFile()) { result.push({ fileDir, fileName,fileStat }); } else if (fileStat.isDirectory()) { loop(fileDir); } }); } loop(filePath); return result;}exports.loopFile = loopFile;exports.loopFileSync = loopFileSync;运行成果 ...

August 12, 2022 · 3 min · jiezi

关于node.js:nodejs-中的path-模块

path.join(path1[, ...]) 连贯门路path.normalize(path) 规范化门路path.resolve([from ...], to) 将 to 参数解析为绝对路径,给定的门路的序列是从右往左被解决的,前面每个 path 被顺次解析,直到结构实现一个绝对路径 规范化门路path.isAbsolute(path) 判断是否是绝对路径path.relative(from, to) 用于将绝对路径转为相对路径,返回从 from 到 to 的相对路径(基于当前工作目录)path.dirname(p) 返回文件夹门路path.basename(p[, ext]) 返回门路中的最初一部分path.extname(p) 返回门路中文件的后缀名path.parse(pathString) 返回门路字符串的对象。path.format(pathObject) 从对象中返回门路字符串,和 path.parse 相同。//__dirname:\pbs\pbs_web_doing1\pbs-web\web\vue\src\utils\ 以后文件所在文件夹门路console.log("111=", path.join(__dirname, "zcp.vue"))console.log("222=", path.normalize("/data//databases///pbs"))console.log("301=", path.resolve(__dirname, "z", 'c', 'p'))console.log("302=",path.resolve(__dirname, "/z", '/c', '/p'))console.log("303=",path.resolve(__dirname, "z", 'c', '/p'))console.log("304=",path.resolve("test.vue"))console.log("=",path.isAbsolute("/pbs/pbs_web_doing1/pbs-web/web/vue"))console.log("=",path.isAbsolute("../../pbs-web/web/vue"))111= e:\pbs\pbs_web_doing1\pbs-web\web\vue\src\utils\zcp.vue222= \data\databases\pbs301= e:\pbs\pbs_web_doing1\pbs-web\web\vue\src\utils\z\c\p302= e:\p303= e:\p304= e:\pbs\pbs_web_doing1\pbs-web\web\vue\test.vue444= true555= false

August 11, 2022 · 1 min · jiezi

关于node.js:Nodejs工程师养成计划某课完结内置文档资料

download:Node.js工程师养成打算【某课】完结内置文档资料用Flexbox和Grid使网页页脚保持在页面的底部如果你次要是处理SPA开发,你可能会困惑为什么这个问题仍然存在,但它仍然有可能找到你的页脚沉没起来的原因: 登录页面博客/新闻文章(没有广告...)流程的间歇性页面,如确认口头产品列表页日历事件的细节 有两种方法可能用古代CSS来处理:flexbox和grid。这里是演示,默认为flexbox方法。如果你打开完整的Codepen,你可能将$method 变量换成grid ,以查看该代替打算。持续浏览演示,了解每种方法。Flexbox方法#这种方法是通过定义来实现的。body { min-height: 100vh; display: flex; flex-direction: column;} footer { margin-top: auto;} / Optional /main { margin: 0 auto; / or: align-self: center / max-width: 80ch;}复制代码它是如何工作的#首先,咱们确保body 元素将至多拉伸到屏幕的全副高度,min-height: 100vh 。如果内容较短,这将不会触发溢出(例外:某些移动阅读器),它将容许内容根据需要持续拉伸高度。设置flex-direction: column ,可能在保留重叠的块元素方面保持失常文档流的行为(假设body 的间接子元素确实都是块元素)。Flexbox的劣势在于利用了margin: auto 的行为。这个怪异的技巧将导致边距填补它所设置的我的项目和它在相应方向上最近的兄弟姐妹之间的任何空间。设置margin-top: auto ,可能无效地将页脚推到屏幕的底部。骗局#在演示中,我在main 中增加了一个outline ,以证实在flexbox方法中,main 元素并没有填补高度。这就是为什么咱们必须使用margin-top: auto 的技巧。这对你来说不可能有什么影响,但如果有的话,请看网格方法,它可能将main ,以填补可用空间。网格方法#这种方法是通过设置实现的:body { min-height: 100vh; display: grid; grid-template-rows: auto 1fr auto;} / Optional /main { margin: 0 auto; max-width: 80ch;}复制代码它是如何工作的#咱们为这种方法保留了min-height: 100vh ,但咱们随后使用了grid-template-rows ,以正确划分空间。这种方法的怪招是使用非凡的网格单位fr 。fr 意义是 "分数",使用它申请阅读器计算出可用的 "分数 "空间,以调配给该列或行。在这种情况下,它填补了页眉和页脚之间的所有可用空间,这也解决了flexbox方法的 "陷阱"。哪个更好?#看到grid之后,你可能会有一霎时感觉它显然更胜一筹。然而,如果你在页眉和页脚之间增加更多的元素,你需要更新你的模板(或者确保总是有一个包装元素,如div ,以不影响任何嵌套语义/档次)。另一方面,flexbox方法可用于两头部分有多个块状元素的各种模板--例如,一系列的<article> 元素,而不是繁多的<main> ,用于存档页面。因此,与所有技术一样,这取决于我的项目 :)然而,咱们都可能批准,具备这些古代的CSS布局方法是很了不起的! ...

August 9, 2022 · 1 min · jiezi

关于node.js:Nodejs工程师养成计划15章完结fen享

download:Node.js工程师养成打算云盘无密Node为什么要学习Nodejs企业需要 具备服务端开发教训更好全栈工程师根本的网站开发能力 服务端前端运维部署相干工作 Node是什么Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。  Node.js 应用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。目前稳固版本:14.15.1 LTS(Long Term Support) 长期反对版本装置node官网下载=>一键式装置,点点点就能够进行装置。ps:如果windows电脑的同学在装置时批改了装置门路,请自行去批改环境变量 当然当初node的最新版本是14.15.1,大家能够当初下载最新版本进行装置 示意装置胜利筹备工作 运行node程序console.log('hello node');console.log('run my use:node 01-runnode');复制代码运行:node 01-runnode.js 每次批改js文件须要从新执行才会失效,装置nodemon 能够监督文件改变,主动重启npm i -g nodemon 当前运行 用nodemon 01-runnode.js 调式node程序:Debug-Start Debugging REPL(交互式解释器) 表达式运算应用变量多行表达式REPL命令 ctrl + c - 退出以后终端。ctrl + c 按下两次 - 退出 Node REPL。ctrl + d - 退出 Node REPL.向上/向下 键 - 查看输出的历史命令tab 键 - 列出以后命令.help - 列出应用命令.break - 退出多行表达式.clear - 退出多行表达式.save filename - 保留以后的 Node REPL 会话到指定文件.load filename - 载入以后 Node REPL 会话的文件内容。 ...

August 9, 2022 · 2 min · jiezi

关于node.js:Nodejs工程师养成计划完整无密内置文档资料

download:Node.js工程师养成打算残缺无密内置文档资料分库分表订单全局ID概述分库分表后涉及到的另一个问题就是主键如何保障唯一且自增。以前单库单表的时候只需要利用数据库个性进行自增即可,现在因为是各自独立的库表,数据库之间的主键自增无奈进行交互,比如数据库1的订单明细表主键自增到了1001,数据库2的订单明细表主键现在是1000,如果现在往数据库2的订单明细表中插入一条数据,这个时候获取到的主键ID会是1001,这样就会造成业务上的主键冲突。全局ID为理解决订单明细表主键的重复问题。靠数据库的主键自增是无奈做到了。如何解决这个问题呢?可能给我的项目中引入一个全局唯一的ID服务,这个服务就是用来生成全局唯一ID的,每次生成的ID都不一样,可能保障主键的唯一性。 全局ID算法全局ID需要保障如下的个性: 全局唯一:必须保障ID是全局性唯一的,基本申请 高性能:高可用低延时,ID生成响应要块,否则反倒会成为业务瓶颈 高可用:100%的可用性是骗人的,然而也要有限靠近于100%的可用性 好接入:要秉着拿来即用的设计原则,在零碎设计和实现上要尽可能的简略 趋势递增:最好趋势递增,这个申请就得看具体业务场景了,一般不严格申请 罕用的全局ID算法如下: 雪花算法Snowflake百度uid-generator美团Leaf滴滴Tinyid 雪花算法 次要分为 4 个部分: 是 1 个 bit:0,这个是无意义的。是 41 个 bit:示意的是工夫戳。是 10 个 bit:示意的是机房 id,0000000000,因为我传进去的就是0。是 12 个 bit:示意的序号,就是某个机房某台机器上这一毫秒内同时生成的 id 的序号,0000 0000 0000。 1 bit,是无意义的: 因为二进制里第一个 bit 为如果是 1,那么都是正数,然而咱们生成的 id 都是负数,所以第一个 bit 对立都是 0。41 bit:示意的是工夫戳,单位是毫秒。 41 bit 可能示意的数字多达 2^41 - 1,也就是可能标识 2 ^ 41 - 1 个毫秒值,换算成>年就是示意 69 年的工夫。10 bit:记录工作机器 id,代表的是这个服务最多可能部署在 2^10 台机器上,也就是 1024 台机器。 然而 10 bit 里 5 个 bit 代表机房 id,5 个 bit 代表机器 id。意义就是最多代表 2 ^ 5 个机房(32 个机房),每个机房里可能代表 2 ^ 5 个机器(32 台机器),这里可能随便拆分,比如拿出4位标识业务号,其余6位作为机器号。可能随便组合。12 bit:这个是用来记录同一个毫秒内产生的不同 id。 12 bit 可能代表的最大正整数是 2 ^ 12 - 1 = 4096,也就是说可能用这个 12 bit 代表的数字来分别同一个毫秒内的 4096 个不同的 id。也就是同一毫秒内同一台机器所生成的最大ID数量为4096 ...

August 8, 2022 · 3 min · jiezi

关于node.js:node中childProcess库spawn底层流程

对应Node多过程exec办法执行流程源码剖析 文章,exec/execFile/fork办法都是执行的spwan办法;这篇文章也是重点去梳理spawn办法的设计思路 源码剖析目前的源码是nodev12版本的;整体思路是差不多的,可供参考学习core-modules/child_process.js spawn办法 function spawn(file, args, options) { const opts = .... // 标准化参数 const child = new ChildProcess(); .... child.spwan({ file: opts.file, args: opts.args, cwd: options.cwd, .... }); return child; }internal/child_process.js 将依照执行流程,重点介绍这几个办法ChildProcess.prototype.spawn办法ChildProcess.prototype.spawn = function(options) { let i =0; if(options === null || typeof options !== 'object') { // options 如果不存在抛出异样 throw new ERR_INVALID_ARG_TYPE('options', 'Object', options) } let stdio = options.stdio || 'pipe'; // 规范的输入接口,通常采纳pipe(管道) stdio = getValidStdio(stdio, false); // pipe(管道)在这创立的;上面有getValidStdio办法源码的阐明; const .... stdio = options.stdio = stdio.stdio; // [ // {type: 'pipe', readable: true, writable: false, handle: Pipe}, // {type: 'pipe', readable: false, writable: true, handle: Pipe}, // {type: 'pipe', readable: false, wriatable: true, handle:Pipe} // ]; .... const err = this._handle.spawn(options); // 调用process_wrap进行实例化,创立子过程;err为0;示意子过程创立胜利。 // 谬误的err解决 if (err === UV_EACCES || err === UV_EAGAIN || ..... ) { process.nextTick(onErrorNT, this, err); }; .... this.pid = this._handle.pid; // pid 为过程的id; for (i = 0; i<stdio.length; i++) { // 建设父子之间的通信 const stream = stdio[i]; // 流,指的是每一条pipe; ... if(stream.handle){ stream.scoket = creatSocket( this.pid !== 0 ? stream.handle:nunll, i > 0 ); // 失去socket实例; }; }; }; ... // 输入流,输入流是i大于0 for (i>0 && this.pid!==0) { ... stream.socket.on('close', ()=>{ // 绑定了close监听 maybeClose(this); }); ... }; // 后续的谬误流也会绑定colse监听 ... // 别离 创立输出流、输入流、谬误流;上面是整顿好后的后果 // socket 通信被创立实现 this.stdin = stdio.length >= 1 && stdio[0].socket !== undefined ? stdio[0].socket : null; this.stdout = stdio.length > 2 &&stdio[1].socket!== undefined ? stdio[1].socket : null; this.stderr = stdio.length >= 3 && stdio[2].socket !== undefined ? stdio[2].socket : null; // stdio对象:从输入输出流中拿到socket对象 // [ // {type: 'pipe', readable: true, writable: false, handle: Pipe, socket: Socket}, // {type: 'pipe', readable: false, writable: true, handle: Pipe, socket: Socket}, // {type: 'pipe', readable: false, wriatable: true, handle:Pipe, socket:Socket} // ]; // 将数组中的每一项的socket拿进去赋值到stdin、stdout、stderr;在返回回调函数中,咱们会应用 stdout.on(‘data’, function()=>{});".on"的形式来调用是因为,返回的是一个socket对象,socket对象的应用办法就是采纳on的形式。 ... this.stdio = []; if (i=0; i<stdio.length; i++) { // 将三个流都放在stdio;别离是,输出流、输入流、谬误流;三个socket; this.stdio.push(stdio[i].socket === undefined ? null : stdio[i].socket); // fork,就会走进这里,创立两边通信的管道 if (ipc !== undefined) setUpChannel(this, ipc); return err; }};getValidStdio办法function getValiStdio(stdio, sync) { var ipc; var ipcFd; if(typeof stdio === 'string') { stdio = stdioStringToArray(stdio); // 转化为数组 ['pipe', 'pipe', 'pipe'] [输出流、输入流、谬误流]; }else if(!Array.isArray(stdio)){ throw new ..... //谬误输入 }}while(stdio.length < 3)stdio.push(undefined);stdio = stdio.reduce((acc, stdio, i) => { if (stdio == null) { ... }; if(stdio === 'ignore') { // 传递的值是ignore,输入输出流不会创立,执行这个命令,不会收到反馈,静默形式去执行子过程。 ... }else if(stdio === 'pipe' || typeof stdio === 'number' && stdio < 0) { // 对不同的管道进行不同的输出设置: // 输出管道:子过程只能读不能写; // 输入管道:子过程只能写不能读; // 从这能够看出是单向的管道,不是双向的 var a = { tyep:'pipe', readable: i === 0, writable: i !== 0 }; if(!sync) { a.handle = new pipe (PipeConstants.SOCKET); // Pipe = internalBinding('pipe_warp);引入的c++源码;用于创立管道 } .... // 以上形式在创立输入管道 return { stdio, // Array;pipe的个性,如上增加的ver a ;输出和输入管道; ipc, // fork中的双向通信管道,ipc通信; ipcFd };})createSocketfunction createSocket (pipe, readable) { // 调用了net上面的Socket办法 return net.Socket({handle: pipe, readable, writable: !readable}); // 这个办法后续会在callback的时候具体详解,和C++中有交互;先看返回后果,一个socket实例、创立了callback函数;}总结child.spawn办法的实现通过getValidStdio 来生成pipe(管道)创立管道实例;有三个别离是:输出管道、输入管道、error管道;没有创立socket通信;normalizeSpawnArgs进行参数的校验this._handle.spawn创立子过程调用createSocket办法,将下面创立好的pipe和子过程当中的socket进行绑定;每一个pipe对应一个socket,用于父子过程通信;写入就用写入的pipe,读取就用读取的pipe,有异样存在就用异样的pipe;

August 7, 2022 · 3 min · jiezi

关于node.js:Wallysnew-productMT7915MT975-4radios

WiFi6 MiniPCIe Module 2T2R 2×2.4GHz 2x5GHz MT7915 MT7975 MT7915/MT7975/IPQ6000/IPQ6018/IPQ6010/IPQ4019/IPQ4029/ipq4018/IPQ4028/IPQ8072/IPQ8072A/IPQ8074/IPQ8074A/IQCN6024/QCN9074/QCN9072/QCN9024/IPQ5018/AR9223/QCA9880/QCA9882 /AR9582/AR9531/AR9344 /AX200NGW Wallys Communications (SuZhou) Co., Ltd., http://www.wallystech.com,which is a professional supplier specializing in product design, manufacturing and offering superior OEM/ODM/JDM services in wireless communications. As a specialized manufacturer and exporter for these products in China,We sincerely hope to establish business relations with your esteemed corporation.  BY:Wallys Communications (Suzhou ) Co., LTDEMAIL:sales3@wallystech.com DR7915 https://www.wallystech.com/Ne... https://www.youtube.com/watch... IntroductionDR7915 is a WiFi6 Mini PCIe Module 2T2R based on Mediatek MT7915DAN which is a WiFi Mini PCIe single chip which supports 1800 Mbps PHY rate with PCIe2.1. It fully complies with IEEE 802.11ax/ac and IEEE 802.11 ac/a/b/g/n standards, offering feature-rich wireless connectivity at high standards, and delivering reliable, cost-effective throughput from an extended distance. Optimized RF architecture and base band algorithms provide superb performance and low power consumption. Intelligent MAC design deploys a high efficient offload engine and hardware data processing accelerators which completely offloads Wi-Fi task of the host processor. MT7915DAN is designed to support standard based features in the areas of security, quality of service and international regulations, giving end users the greatest performance any time and in any circumstance. MT7915DAN is designed to support high data throughput over WiFi. The host interface PCIe are integrated to provide stable bandwidth between the host platform and MT7915DAN. ...

August 3, 2022 · 3 min · jiezi

关于node.js:NVM-快速安装教程

nvm作为一款node的版本管理工具,在前端开发中是必不可少的,然而因为GitHub的特殊性,导致很多人是无奈用官网教程装置胜利,本文旨在整顿出如德芙般丝滑的装置教程。 本文介绍的装置办法,你能够了解为通过仓库镜像的形式装置。如果你能失常稳固拜访GitHub,则无需通过本文形式装置。 仓库地址: GitHub: https://github.com/ineo6/nvmGitLab: https://gitlab.com/mirrorx/nvm装置脚本装置选用上面任意一个脚本都行,留神mac上没有wget。 export NVM_SOURCE=https://gitlab.com/mirrorx/nvm.gitcurl -o- https://gitlab.com/mirrorx/nvm/-/raw/master/install.sh | bashexport NVM_SOURCE=https://gitlab.com/mirrorx/nvm.gitwget -qO- https://gitlab.com/mirrorx/nvm/-/raw/master/install.sh | bash测验装置是否胜利command -v nvm执行后如果显示nvm则示意曾经装置胜利。 如果遇到nvm命令找不到的问题,请查阅文末的“FAQ”。 更新从新执行装置脚本即可。 配置1. 设置为零碎默认node因为nvm装置的后果都是上面这样的格局: /Users/neo/.nvm/versions/node/v14.17.4/bin/node为了确保在所有的shell以及ide中都能够失常工作,咱们须要设置把nvm装置的node设置为零碎默认。 nvm alias default node2. 设置node镜像这里是给装置node设置镜像。 export NVM_NODEJS_ORG_MIRROR=https://npmmirror.com/mirrors/nodenvm install node// 或者NVM_NODEJS_ORG_MIRROR=https://npmmirror.com/mirrors/node nvm install 4.2长期替换能够应用上面的设置: echo 'export NVM_NODEJS_ORG_MIRROR="https://npmmirror.com/mirrors/node"' >> ~/.zshrc留神! 下面脚本是把配置写入文件.zshrc,你如果对此不理解,请参考FAQ,确定是否更换为.bash_profile。 FAQnvm命令找不到(command not found)须要手动配置环境变量。 执行命令echo $SHELL,依据后果判断写入的文件: /bin/zsh => zsh => .zshrc/bin/bash => bash => .bash_profile.zshrcecho 'export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> ~/.zshrcsource ~/.zshrc.bash_profileecho 'export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> ~/.bash_profilesource ~/.bash_profile更多像nvm这样装置艰难的工具还有不少,我也始终有出一个系列合集的想法,如果你也期待更多这方面的文章,欢送关注我,以便最快获取最新动静。 ...

August 2, 2022 · 1 min · jiezi

关于node.js:Node网络编程

TCPNagle算法如果每次发送一个很小的数据包,比方一个字节内容的数据包而不优化,就会导致网络中只有极少数无效数据的数据包,这会导致节约大量的网络资源。Nagle算法针对这种状况,要求缓存区的数据达到肯定数据量或者肯定工夫后才将其收回,所以数据包将会被Nagle算法合并,以此来优化网络。这种优化尽管进步了网络带宽的效率,但有的数据可能会被提早发送。 在Nodejs中,因为TCP默认启动Nagle算法,能够调用socket.setNoDelay(ture)去掉Nagle算法,使得write()能够立刻发送数据到网络中。但须要留神的是,只管在网络的一端调用write()会触发另一端的data事件,然而并不是每次write()都会触发另一端的data事件,在敞开Nagle算法后,接收端可能会将接管到的多个小数据包合并,而后只触发一次data事件。也就是说socket.setNoDelay(ture)只能解决一端的数据粘包问题。 什么是粘包?在组包过程中,把上一个包的内容与下一个包里的粘在了一起被谬误地当成了一个数据包解析了进去。这就是所谓的粘包。 粘包呈现的根本原因是不确定音讯的边界。接收端在面对"无边无际"的二进制流的时候,基本不晓得收了多少 01 才算一个音讯。一不小心拿多了就说是粘包。其实粘包基本不是 TCP 的问题,是使用者对于 TCP 的了解有误导致的一个问题。 只有在发送端每次发送音讯的时候给音讯带上辨认音讯边界的信息,接收端就能够依据这些信息辨认出音讯的边界,从而辨别出每个音讯。 通过拆包封包的形式解决粘包计划node.js中,不会依照发送端的write写入对应触发接收端的data事件,它会有以下3种状况: 发送端屡次write()的数据可能被打包成一个数据包发送到接收端。发送端通过write()一次写入的数据可能因为体积过大被截断到多个数据包中发送端通过write()一次写入打包成一个数据报发送到接收端咱们要解决就是前2中状况。TCP是基于流的传输机制,那么它的数据程序在传输过程中是确定的先进先出准则。所以,能够通过在每次write()在数据头部增加一些标识,将每次write()传输的数据距离开,而后在接收端基于这些距离数据的标识将数据拆分或合并。

August 2, 2022 · 1 min · jiezi

关于node.js:Node多进程exec方法执行流程源码分析

在自研脚手架阶段,对node的同步/异步执行进行了应用;然而未能深层次去理解为何这么设计,这次也是通过问题的形式来进行了一些思考。⚠️注: 目前是12版本的node;你可能当初用的版本是16版以上用TS来写的;然而node的基本上的思路是没有太多变动的。思考问题一:exec和execFile到底什么区别?问题二: 为什么exec/execFile/fork都是通用spawn实现的,spawn的作用到底是什么?问题三:为什么spawn没有回调;exec和execFile可能回调?问题四:为什么spawn调用后,需手动调用child(spawn返回值).stdout.on('data',callback);spawn.stdout和spawn.stderr到底是什么?问题五:为什么有data/errer/exit这么多种回调;他们的执行程序到底是什么?一、 源码剖析源码分析方法:依据办法的执行调用程序来进行剖析源码exec源码剖析源码目录构造child_process.js execexecFilespawninternal/child_process.js ChildProcessspawn代码执行流程执行本地代码 首先在本地创立index.js; const cp = require('child-process'); const child = cp.exec('ls -la|grep node_modules', function(err, stdout stderr){ console.log(err, stdout, stderr); }); 执行 cp.exec办法 将会调用node的内置库【child_process】中的【exec】办法,进行参数的标准化解决【normalizeExecArgs】function exec (command, options, callback) { const opts = noramlizeExeArgs(command, options, callback); return module.exports.execFile(opts.file, opts.optionns, opts.callback);}入参解决:opts:{file : "ls -al|grep node_modules",options : {shell : ture},callback : .....,}入参解决后的后果:file 是输出的命令options 增加了shell为truecallback 没有变动返回后果:return module.exports.execFile间接调用execFile办法通过exec办法中的noramilizeExecArgs办法将参数转化成execFile办法的参数一样; 进入execFile办法 a. 首先还是会进行一个参数的标准化解决【normalizeExecFileArgs】 b. 调用spawn child办法,次要目标是创立一个子过程并且对它进行异步执行const child = spawn (file, args, { cwd: options.cwd, env: options.env, gid: options.gid, uid: options.uid, shell: options.shell, .....});spawn参数阐明:file: "ls -al|grep node_modules",agrs: 没有参数,object:{shell: true}; 中只有shell参数显示true,须要用外部的shell脚本去执行. ...

August 1, 2022 · 2 min · jiezi

关于node.js:vue单文件组件SFC规范

图片.vue 文件蕴含三种类型的顶级语言块 <template>、<script> 和 <style>。 一个 .vue 文件能够蕴含多个 <style> 标签,能够在 .vue 文件中增加额定的自定义块来实现我的项目的特定需要,例如 <docs> 块https://vue-loader.vuejs.org/...。 每个vue文件的根节点必须为 <template>,且这个 <template> 下只能且必须有一个根 <view> 组件。 <template> <view> 留神必须有一个view,且只能有一个根view。所有内容写在这个view上面。 </view> </template> <script> export default { } </script> <style> </style>https://ask.dcloud.net.cn/art... npm 全称为 Node Package Manager,是一个基于Node.js的包管理器,也是整个Node.js社区最风行、反对的第三方模块最多的包管理器。 Node.js 是一个开源和跨平台的 JavaScript 运行时环境,Node.js 在浏览器之外运行 V8 JavaScript 引擎(Google Chrome 的内核)。 webpack 是 JavaScript 打包器(module bundler) I 组件标准组件是视图层的根本组成单元,组件是一个独自且可复用的功能模块的封装,容许咱们应用小型、独立和通常可复用的组件构建大型利用。 页面是一种非凡的组件图片 1.1 组件的组成部分每个组件,包含如下几个局部: 以组件名称为标记的开始标签和完结标签组件内容组件属性、组件属性值。所有组件与属性名都是小写,单词之间以连字符-连贯。 1.2 公共属性列表属性名 类型 形容 注解id String 组件的惟一标示 个别用于获取组件上下文对象(如:VideoContext),须要放弃整个页面惟一ref String vue中组件的惟一标示 用来给子组件注册援用信息class String 组件的款式类 在对应的 css 中定义的款式类style String 组件的内联款式 能够动静设置的内联款式hidden Boolean 组件是否暗藏 所有组件默认是显示的data-* Any 自定义属性 组件上触发的事件时,会发送给事件处理函数@* EventHandler 组件的事件 还有一类非凡属性以v-结尾,称之为vue指令,如v-if、v-else、v-for、v-model。 ...

July 30, 2022 · 3 min · jiezi

关于node.js:Nodejs提供https服务

在服务器上的接口服务可能是通过Nginx转发,如果是https协定那么监听的是443端口。当然接口服务也能够间接拜访服务器端 Node.js 监听的端口如:3100,不过你须要凋谢服务器的防火墙端口才能够。这篇文章介绍一下我曾遇到的问题,问什么要开启https服务?Node.js如何配置证书?Express.js如何配置证书?Why HTTPS?HTTPS是一种通过计算机网络进行平安通信的传输协定,经由HTTP进行通信,利用SSL/TLS建设全信道,加密数据包。HTTPS应用的次要目标是提供对网站服务器的身份认证,同时爱护替换数据的隐衷与完整性。 降级到HTTPS的益处对SEO更加敌对解锁古代浏览器的一些高级性能(service workers,WebUSB,Bluetooth)也须要 HTTPS的反对。同源策略的限度如果你的域名是 www.iicoom.top ,有一个前端我的项目跑在这个 http://www.iicoom.top 的地址下,这个我的项目是能够拜访 http://www.iicoom.top 提供的动态资源的。 然而如果前端我的项目跑在 https://www.iicoom.top,就无法访问 http://www.iicoom.top 提供的动态资源。 浏览器会抛出上面的谬误: [blocked] The page at 'https://www.iicoom.top' was loaded over HTTPS but ran insecure content from 'http://www.iicoom.top': this content should also be loaded over HTTPS.所以,咱们须要把协定降级为 HTTPS。 Node.js启动https服务官网文档 const https = require('https');const fs = require('fs');const options = { key: fs.readFileSync('key.pem'), cert: fs.readFileSync('cert.pem')};https.createServer(options, function (req, res) { res.writeHead(200); res.end("hello world\n");}).listen(8000);然而如果你应用了express框架,怎么做呢?express配置https服务const express = require('express');const fs = require('fs');const https = require('https');app.get('/', (req, res) => { res.send('Hello World!');});const privateKey = fs.readFileSync('./cert/iicoom.key');const certificate = fs.readFileSync('./cert/iicoom.crt');https.createServer({ key: privateKey, cert: certificate,}, app).listen(port, () => { console.log(`Example app listening at http://localhost:${3100}`);});这样,就把网站、接口、动态资源都升级成了https协定了。心愿对你有帮忙。 ...

July 30, 2022 · 1 min · jiezi

关于node.js:MongoDB数据库数据突然消失-数据丢失

查找起因感觉是被黑了看了一眼数据库给我整笑了 内容是 All your data is a backed up. You must pay 0.05 BTC to 1Kz6v4B5CawcnL8jrUvHsvzQv5Yq4fbsSv 48 hours for recover it. After 48 hours expiration we will leaked and exposed all your data. In case of refusal to pay, we will contact the General Data Protection Regulation, GDPR and notify them that you store user data in an open form and is not safe. Under the rules of the law, you face a heavy fine or arrest and your base dump will be dropped from our server! You can buy bitcoin here, does not take much time to buy https://localbitcoins.com or https://buy.moonpay.io/ After paying write to me in the mail with your DB IP: rambler+14ebs@onionmail.org and/or mariadb@mailnesia.com and you will receive a link to download your database dump.翻译成人话就是转我0.05BTC(约16103人民币)就给你复原,48小时不给我转,我就黑你服务器 ...

July 29, 2022 · 1 min · jiezi

关于node.js:Nodejs实现分片上传

大文件上传会耗费大量的工夫,而且中途有可能上传失败。这时咱们须要前端和后端配合来解决这个问题。解决步骤: 文件分片,缩小每次申请耗费的工夫,如果某次申请失败能够独自上传,而不是从头开始告诉服务端合并文件分片管制并发的申请数量,防止浏览器内存溢出当因为网络或者其余起因导致某次的申请失败,咱们从新发送申请文件的分片与合并在JavaScript中,FIle对象是' Blob '对象的子类,该对象蕴含一个重要的办法slice,通过该办法咱们能够这样宰割二进制文件: <!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> <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.24.0/axios.min.js"></script></head><body> <input type="file" multiple="multiple" id="fileInput" /> <button onclick="SliceUpload()">上传</button> <script> function SliceUpload() { const file = document.getElementById('fileInput').files[0] if (!file) return // 文件分片 let size = 1024 * 50; //50KB 50KB Section size let fileChunks = []; let index = 0; //Section num for (let cur = 0; cur < file.size; cur += size) { fileChunks.push({ hash: index++, chunk: file.slice(cur, cur + size), }); } // 上传分片 const uploadList = fileChunks.map((item, index) => { let formData = new FormData(); formData.append("filename", file.name); formData.append("hash", item.hash); formData.append("chunk", item.chunk); return axios({ method: "post", url: "/upload", data: formData, }); }); await Promise.all(uploadList); // 所有分片上传实现,告诉服务器合并分片 await axios({ method: "get", url: "/merge", params: { filename: file.name, }, }); console.log("Upload to complete"); } </script></body></html>并发管制如果文件很大,这样切分的分片会很多,浏览器短时间内就会发动大量的申请,可能会导致内存耗尽,所以要进行并发管制。 ...

July 26, 2022 · 3 min · jiezi

关于node.js:Puppeteer-前端生成海报新姿势

原文参考我的公众号文章 前端生成海报新姿态 Puppeteer 以往都是怎么生成海报的?在开发中常常会遇到「生成海报长图」的需要,个别都是这么做的: 后端生成:引入会图库进行绘制前端生成:用原生canvas进行绘制、用一些js库(html-to-canvas)这么用过去的体验就是:无论是谁生成,都会遇到海报上各个元素的定位艰难、款式还原的艰难、动静内容和动静海报尺寸不好把控等问题。 因而,通过一波摸索,接触了puppeteer这个「高级货!」,用完之后,几乎有种相见恨晚的感觉! 所以当初要想生成一个简单的海报或者长图的流程变成了这样: 编写海报承载web页面调用puppeteer截图服务,对web页面进行截图,并返回图片或者图片地址给调用者先看看官网是怎么介绍的?Puppeteer 是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协定管制 Chromium 或 Chrome。Puppeteer 默认以 headless 模式运行,然而能够通过批改配置文件运行“有头”模式。你能够在浏览器中手动执行的绝大多数操作都能够应用 Puppeteer 来实现! 上面是一些示例: 生成页面截图或PDF。抓取 SPA(单页利用)并生成预渲染内容(即“SSR”(服务器端渲染))。主动提交表单,进行 UI 测试,键盘输入等。创立一个时时更新的自动化测试环境。 应用最新的 JavaScript 和浏览器性能间接在最新版本的Chrome中执行测试。捕捉网站的 timeline trace,用来帮忙剖析性能问题。测试浏览器扩大。几乎是「不明觉厉」! 配角退场这篇文章的配角就是 page.screenshot,通过它,咱们能够实现对指标网页(其实也就是承载海报内容的网页)的截图,而后开一个node接口服务,造成高可用的业务接口,将截图后的图片或者图片地址返回给调用者。 间接参考 screenshot文档 就能疾速实现一个截图服务,上面间接上代码,而后再说一些期间遇到的小问题及解决思路。 编写截图外围 screenshotPuppeteer.jsconst path = require("path");const puppeteer = require("puppeteer");function sleep(delay = 1000) { return new Promise((resolve) => { setTimeout(() => { resolve(1); }, delay); });}function loginfo(debug, info) { if (debug) { console.log(info); }}/** * 基于「puppeteer」的服务端截图工具 * @param {*} options {...} 具体见下 @param {*} options.debug: false 是否开启调试 @param {*} options.pageUrl: "" 要截图的web地址 @param {*} options.defaultViewport: { width: 390, height: 844, deviceScaleFactor: 3, isMobile: true, } 是否开启Viewport模拟器 @param {*} options.headless: "" 是否有浏览器界面 @param {*} options.fileName: "" 截图文件保留名称 @param {*} options.fileSavePath: "datasource/poster/" 默认服务器代码写死 @param {*} options.fileType: "jpeg" 截图保留格局 [jpeg, png, webm] @param {*} options.quality: 100 压缩率[0,100],fileType=jpeg时无效 @param {*} options.fullPage: true 是否全屏,边滚动动边截图 @param {*} options.clip: null 指定裁剪区域,fullPage为true时不可用,默认null,容许参数:{ x: 0, y: 0, width: 390, height: 844 } @param {Number} screenshotDelay: 500 页面load后,触发截图之前的【延迟时间】 @param {*} options.closePage: true 截图完敞开页面(默认true敞开) @param {*} options.closeBrowser: true 截图完敞开浏览器(默认true敞开) @param {*} options.cb: null, }; */async function screenshotCore(config = {}) { let options = { debug: false, headless: true, //默认无头 pageUrl: "", //要截图的web地址 defaultViewport: { width: 390, height: 667, deviceScaleFactor: 3, isMobile: true, }, //是否开启Viewport模拟器 fileName: "", //截图文件保留名称 fileSavePath: "datasource/poster/", //默认服务器代码写死 fileType: "jpeg", //截图保留格局 [jpeg, png, webm] quality: 100, //压缩率[0,100],fileType=jpeg时无效 fullPage: true, //是否全屏,边滚动动边截图 clip: null, //指定裁剪区域,fullPage为true时不可用,默认null,容许参数:{ x: 0, y: 0, width: 390, height: 844 } screenshotDelay: 500, //页面load后,触发截图之前的【延迟时间】 closePage: true, //截图完敞开页面(默认true敞开) closeBrowser: true, //截图完敞开浏览器(默认true敞开) cb: null, ...config, }; loginfo( options.debug, `screenshotCore options: ${JSON.stringify(options, " ", "\t")}` ); let webpagePath = options.pageUrl || null; let saveType = options.fileType || "jpeg"; let file = `${options.fileName}.${saveType}`; let relativePath = `${options.fileSavePath}${file}`; let savePath = path.join(__dirname, "..", relativePath); let saveQuality = options.quality || 100; let isFullPage = options.fullPage || true; let clipArea = options.clip || null; let browser = null; let page = null; const errHandler = (msg, err) => { return { error: 1, msg, errMsg: err.message || err.msg, err, }; }; const successHandler = (msg, data = {}) => { return { error: 0, msg, data, }; }; const closeAll = async() => { if (options.closePage) { await page.close(); } if (options.closeBrowser) { await browser.close(); } }; return new Promise(async(resolve, reject) => { try { // 启动浏览器 browser = await puppeteer.launch({ args: ["--no-sandbox", "--disable-setuid-sandbox"], //如果报“No usable sandbox!” // slowMo: 100, //加快浏览器执行速度,不便测试察看 headless: options.headless, //是否为无界面拜访浏览器 defaultViewport: options.defaultViewport || null, }); } catch (err) { closeAll(); return reject(errHandler("POSTER利用启动失败", err.msg || err)); } try { // 新建页面 page = await browser.newPage(); page.setDefaultNavigationTimeout(60000); //超时报错timeout工夫,默认30s,0示意无限度 } catch (err) { closeAll(); return reject(errHandler("puppeteer关上新页面失败", err)); } // page.on("load", async () => { // loginfo(options.debug, "Page loaded!"); // await sleep(options.screenshotDelay); // do screenshot ... // }); // let reqNum = 0; // page.on("request", async (req) => { // let method = req.method(); // let url = req.url(); // console.log("request:", ++reqNum); // }); // let repNum = 0; // page.on("response", async (rep) => { // let url = rep.url(); // let status = rep.status(); // console.log("response:", ++repNum); // }); try { // 关上指标页面 { waitUntil: "networkidle0"} 示意以后页面500ms内无http申请,再返回 await page.goto(webpagePath, { waitUntil: "networkidle0" }); } catch (err) { closeAll(); return reject(errHandler("puppeteer关上指标网页失败", err)); } try { // 开始截图 await sleep(options.screenshotDelay); await page.screenshot({ path: savePath, //在服务器上的存储地位 type: saveType, quality: saveQuality, fullPage: isFullPage, clip: clipArea, }); loginfo(options.debug, `截图文件存储在了: ${savePath}`); let retData = { file, type: saveType, quality: saveQuality, }; resolve(successHandler("海报生成胜利", retData)); options.cb && options.cb(page); } catch (err) { reject(errHandler("puppeteer截图失败", err)); } closeAll(); });}module.exports = { screenshotCore,};调用示例const { screenshotCore } = require("./screenshotPuppeteer");screenshotCore({ pageUrl: "www.baidu.com", fileName: `capture_${+new Date()}` }) .then((res) => { console.log("success:", res); }) .catch((err) => { console.log("failed:", err); });总结一些遇到的问题puppeteer.launch启动报错比方在本地开发没问题,部署到Linux服务器之后,遇到No usable sandbox! 或 ...setuid... ,须要在启动配置中减少 args: ["--no-sandbox","--disable-setuid-sandbox"] ...

July 25, 2022 · 3 min · jiezi

关于node.js:node生成word文档

需要最近有我的项目须要用到生成word文档,平时常常用的都是通过模板生成,外面变量应用占位符替换,益处是快捷、不便、简略、不须要通过代码调word款式,确定是很多库不反对图片绘制(很多都是付费性能),找一圈,发现一个很有意思的库,正好也满足咱们的需要,特此分享一下 依赖// https://docx.js.org/#/npm i docx // https://www.npmjs.com/package/downloadnpm i download阐明,因为docx绘图只反对文件流,所以要把网络文件下载到本地转成buffer 代码话不多说,上代码 import * as fs from "fs"import { Document, Packer, Paragraph, TextRun, ImageRun, HeadingLevel, AlignmentType, convertInchesToTwip, Table, TableRow, TableCell, WidthType, VerticalAlign, BorderStyle } from "docx"const download = require('download')// 性别enum Gender { Male = 'male', Female = 'female'}// 选手type PlayerSchema = { name: string gender: string idCard?: string birthday?: string weight?: string remark?: string avatar?: string localAvatar?: string level: string}type GroupSchema = { // gender: Gender institution: string leader: string phone: string coach: string doctor: string players: PlayerSchema[]}// 所有数据interface DataSchema { [key: string]: GroupSchema}// 表格无边框const noBoder = { top: { style: BorderStyle.NIL, size: 0, color: 'FFFFFF' }, bottom: { style: BorderStyle.NIL, size: 0, color: 'FFFFFF' }, left: { style: BorderStyle.NIL, size: 0, color: 'FFFFFF' }, right: { style: BorderStyle.NIL, size: 0, color: 'FFFFFF' }}// 删除下载的照片及文件夹function delStaticFile(groupNames: string[]) { for (let groupName of groupNames) { if (fs.existsSync(groupName)) { const files = fs.readdirSync(groupName) files.map((file: string) => { let curPath = groupName + "/" + file // 删除选手招聘 fs.unlinkSync(curPath) }) fs.rmdirSync(groupName) } }}// 生成wordasync function generate (data: DataSchema) { const groupNames = Object.keys(data) // 比拟毛糙的管制单元格长度逻辑 const longHeaders = ['身份证号', '备注'] // 下载近程资源到本地 for (let groupName of groupNames) { if (!fs.existsSync(groupName)) { fs.mkdirSync(groupName) } const players = data[groupName].players for (let player of players) { if (player.avatar) { const avatarArr = player.avatar.split('/') const fileName = `${groupName}/${avatarArr[avatarArr.length - 1]}` if (!fs.existsSync(fileName)) { await download(player.avatar, groupName) } // 下载后的本地的资源门路 player.localAvatar = fileName } } } // 须要多个文件合一 const sections = groupNames.map(groupName => { const info = data[groupName] const { institution, leader, phone, coach, doctor, players } = info // 标头内容 // let headers = ['序号', '照片', '姓名', '性别', '出生年月', '体重', '级别', '备注'] let headers = ['序号', '照片', '姓名', '性别', '身份证号', '级别', '备注'] // 表格数据 let tableData: any[][] = [] tableData.push(headers) // 填充选手信息 let index = 1 for (let player of players) { tableData.push([ index.toString(), player.localAvatar || '', player.name, player.gender === Gender.Male ? '男' : '女', player.idCard, // player.birthday, // player.weight, player.level, player.remark, ]) index++ } // 表格渲染 const tableRows = tableData.map(colums => { return new TableRow({ children: colums.map(cell => { return new TableCell({ verticalAlign: VerticalAlign.CENTER, width: { // 设置宽度 dxa长度单位 https://stackoverflow.com/questions/14360183/default-wordml-unit-measurement-pixel-or-point-or-inches size: longHeaders.some(j => cell === j) ? 3000 : 800, type: WidthType.DXA, }, children: cell && colums.findIndex(i => i === cell) === 1 && cell !== '照片' ? [new Paragraph({ alignment: AlignmentType.CENTER, children: [ new ImageRun({ // 将图片转化为buffer data: fs.readFileSync(cell), transformation: { width: 100, height: 129, }, }) ] })]: [new Paragraph({ alignment: AlignmentType.CENTER, children:[ new TextRun(cell || '') ] })] }) }) }) }) // 渲染报名表格 const table = new Table({ alignment: AlignmentType.CENTER, rows: tableRows }) return { properties: {}, children: [ // new Paragraph({ // style: "wellSpaced", // children: [ // new TextRun({ // text: '附件 4', // color: '999999', // }) // ], // }), // 表头信息 new Paragraph({ spacing: { before: 400, after: 400 }, style: "Title", text: `自 由 搏 击 比 赛 报 名 表(${groupName === Gender.Male ? '女子' : '男子'})`, heading: HeadingLevel.TITLE, alignment: AlignmentType.CENTER }), // 队伍信息 new Table({ style: "wellSpaced", alignment: AlignmentType.CENTER, borders: noBoder, rows: [ new TableRow({ children: [ new TableCell({ width: { size: 600, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(`单位: `), ], }), new TableCell({ width: { size: 1800, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(`${institution}`) ], }), new TableCell({ width: { size: 700, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(` 领队: `), ], }), new TableCell({ width: { size: 1200, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(`${leader}`) ], }), new TableCell({ width: { size: 1100, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(` 联系电话: `), ], }), new TableCell({ width: { size: 1400, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(`${phone}`) ], }), new TableCell({ width: { size: 700, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(` 教练: `), ], }), new TableCell({ width: { size: 1300, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(`${coach}`) ], }), new TableCell({ width: { size: 700, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(` 队医: `), ], }), new TableCell({ width: { size: 1300, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(`${doctor}`) ], }), ], }), ] }), // 用于段落间隔(table无奈设置spacing属性) new Paragraph({ spacing: { // 通过调整before值来调整段落渐进 before: 400, }, text: ``, }), // 选手信息 table, // 印章和工夫 new Paragraph({ style: "wellSpaced", children: [ new TextRun({ text: '\t\t\t\t报名单位章:\t\t\t\t\t\t', }), new TextRun({ text: '年\t\t' }), new TextRun({ text: '月\t\t' }), new TextRun({ text: '日' }) ] }) ] } }) // 创立整个文档 const doc = new Document({ styles: { paragraphStyles: [ { id: "Title", name: "title", basedOn: "Normal", next: "Normal", quickFormat: true, run: { size: 30, bold: true, color: "000000" } }, { id: "wellSpaced", name: "Well Spaced", basedOn: "Normal", quickFormat: true, paragraph: { indent: { left: convertInchesToTwip(0.5), }, spacing: { before: 400, }, }, }, ], }, sections }) // 生成word文档 Packer.toBuffer(doc).then((buffer) => { fs.writeFileSync("enrolls.docx", buffer) }) // 删除下载的选手照片 delStaticFile(groupNames)}const group: GroupSchema = { institution: '江苏省南京市舜禹团体总部', leader: '王猛(男)', phone: '18861856665', coach: '刘国梁(男)', doctor: '杨永信(女)', players: [ { name: '莱昂纳多迪卡普里奥', gender: Gender.Male, idCard: '320888199001019878', birthday: '1999-01-02', weight: '60kg', avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/13.png', remark: '', level: '60kg' }, { name: '张三', gender: Gender.Male, idCard: '320888199001019878', birthday: '1999-01-02', weight: '60kg', avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/7.png', remark: '', level: '60kg' }, { name: '张三', gender: Gender.Male, idCard: '320888199001019878', birthday: '1999-01-02', weight: '60kg', avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png', remark: '', level: '60kg' }, { name: '张三', gender: Gender.Male, idCard: '320888199001019878', birthday: '1999-01-02', weight: '60kg', avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png', remark: '', level: '60kg' }, { name: '张三', gender: Gender.Male, idCard: '320888199001019878', birthday: '1999-01-02', weight: '60kg', avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png', remark: '', level: '60kg' }, { name: '张三', gender: Gender.Male, idCard: '320888199001019878', birthday: '1999-01-02', weight: '60kg', avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png', remark: '', level: '60kg' }, { name: '张三', gender: Gender.Male, idCard: '320888199001019878', birthday: '1999-01-02', weight: '60kg', avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png', remark: '', level: '60kg' }, { name: '张三', gender: Gender.Male, idCard: '320888199001019878', birthday: '1999-01-02', weight: '60kg', avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png', remark: '', level: '60kg' }, { name: '张三', gender: Gender.Male, birthday: '1999-01-02', weight: '60kg', avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png', idCard: '320888199001019878', remark: '', level: '60kg' }, { name: '张三', gender: Gender.Male, idCard: '320888199001019878', birthday: '1999-01-02', weight: '60kg', avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png', remark: '', level: '60kg' }, { name: '张三', gender: Gender.Male, idCard: '320888199001019878', birthday: '1999-01-02', weight: '60kg', avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png', remark: '', level: '60kg' }, { name: '张三', gender: Gender.Male, idCard: '320888199001019878', birthday: '1999-01-02', weight: '60kg', avatar: 'https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png', remark: '', level: '60kg' } ]}const data: DataSchema = { [Gender.Male]: group, [Gender.Female]: group,}generate(data)

July 23, 2022 · 5 min · jiezi

关于node.js:NodeJs下载安装与配置环境

1.下载http://nodejs.cn/download/ 依据本人电脑配置抉择 2.装置一路next即可,倡议创立本人的装置门路3.检测是否装置胜利node -vnpm -vnpm在装置node时会一起装置,无需独自装置排雷:npm -v 报错:WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead解决方案:将node装置目录下npm/npm.cmd 两个文件内的prefix -g 批改为 prefix --location=global4.配置自定义全局模块装置目录在node装置目录下新建两个文件夹 node_global和node_cache 5.在cmd命令下执行两个指令//配置全局模块寄存门路npm config set prefix "D:\nodejs\node_global"//cache门路npm config set cache "D:\nodejs\node_cache"6.检测刚配置的模块寄存门路关上cmd输出npm config get prefixnpm config get cache7.配置环境变量在零碎变量中新建一个NODE_PATH的变量,门路为node_moduled的门路,依据本人电脑的文件地位配置即可,我这里是D:\NodeJs\node_global\node_modules留神:须要将nodeJS增加到零碎变量Path中当作全局node8.当运行js文件报错找不到装置的模块两种解决形式:1.将零碎变量的node_moduled换到用户变量并须要重启电脑2.在js文件内增加:module.paths.push('D:\NodeJs\node_global\node_modules');

July 22, 2022 · 1 min · jiezi

关于node.js:whistle-使用详细内容待补充

设置申请在列表的显示规定,过滤掉不须要关注的申请:Nwtwork -> settings http://wproxy.org/whistle/web...代理设置rules: 反对 proxy、批改网络申请的返回(批改状态/返回值等)、应用本地文件(作为 执行脚本/返回数据等) http://wproxy.org/whistle/pat...编辑返回数据values: 可作为申请的返回值应用 http://wproxy.org/whistle/rul...拦挡 HTTPS 申请http://wproxy.org/whistle/ins...http://wproxy.org/whistle/web...手机端调试http://wproxy.org/whistle/web...

July 21, 2022 · 1 min · jiezi

关于node.js:Objectassign-vs-Object-Spread

引言在开发过程中,咱们常常能看到 Object.assign 或 Object Spread,这两个办法都能帮忙你失去想要的对象。有的人喜爱用Object.assign,有些人喜爱用 Object Spread,那么用哪一种比拟好呢?这篇文章就是来探讨这个问题。 Object.assign 与 Object Spread 共同点性能都能够实现 object 自有属性(包含 Symbol 属性)的 copy。 示例创立 MyClass class BaseClass { foo() { return 1; } } class MyClass extends BaseClass { bar() { return 2; } } const obj = new MyClass(); obj.baz = function() { return 3; }; obj1[Symbol.for('test')] = 4;应用 Object Spread const clone1 = { ...obj1 }; console.log(clone1); // { baz: [Function], [Symbol(test)]: 4 } console.log(clone1.constructor.name); // Object console.log(clone1 instanceof MyClassTwo); // false应用 Object.assign const clone2 = Object.assign({},obj1) console.log(clone2); // { baz: [Function], [Symbol(test)]: 4 } console.log(clone2.constructor.name); // Object console.log(clone2 instanceof MyClassTwo); // false总结没有把 MyClass 或 BaseClass 的 properties 赋值给新的对象,阐明 只拷贝了object 自有属性(包含 Symbol 属性)。 ...

July 19, 2022 · 1 min · jiezi

关于node.js:官宣SkyWalking-NodeJS-051-补丁版发布

7 月 18 日,Apache SkyWalking 团队在官网博客发表了 SkyWalking NodeJS 0.5.1 补丁版本(CVE-2022-36127)公布的音讯,并揭示所有用户及时降级。 在官网账号 @ASFSkyWalking 的最新推文中,Apache SkyWalking 也对此音讯做了公开发表: 据悉,全新公布的 SkyWalking NodeJS 0.5.1 补丁版本,修复了所有晚期版本 <=0.5.0中的破绽。SkyWalking 倡议所有应用版本 <=0.5.0 的用户降级到此版本。(NodeJS 对已装置的服务具备服务不可用性影响) 如果标头蕴含非法的 SkyWalking 标头,例如(1)OAP 不衰弱,且上游服务的代理无奈建设连贯,则该破绽将导致装置了该代理的 NodeJS 服务不可用。(2) 一些采样机制在上游代理中被激活。 SkyWalking 是国内首个倒退成为 Apache 顶级我的项目的集体开源 APM 我的项目(针对分布式系统的利用性能监控零碎),包含在云原生架构中对分布式系统的监督、跟踪和诊断性能,特地针对微服务、cloud native 和容器化(Docker, Kubernetes, Mesos)架构。 全新公布的 SkyWalking NodeJS 0.5.1 补丁版可应用上面的链接下载镜像: 下载链接:https://skywalking.apache.org... 参考链接:https://twitter.com/ASFSkyWal...

July 18, 2022 · 1 min · jiezi

关于node.js:Nodejs版本升级

最近运行一个前端我的项目时,呈现了Node.js版本与依赖版本不符的问题,如下:error @typescript-eslint/eslint-plugin@5.21.0: The engine "node" is incompatible with this module. Expected version "^12.22.0 || ^14.17.0 || >=16.0.0". Got "14.16.0"error Found incompatible module.正如下面的谬误提醒,本地装置的node版本是14.16.0,于是打算将版本升级到大于16.0.0的版本。 这里介绍一个node版本管理工具,能够不便的治理你本地的版本。 装置命令: npm i n -g如果呈现了上面的谬误,你须要加上 sudo npm i n -g ➜ quick-demo-vue3-ts git:(main) npm i n -gnpm WARN checkPermissions Missing write access to /usr/local/lib/node_modulesnpm ERR! code EACCESnpm ERR! syscall accessnpm ERR! path /usr/local/lib/node_modulesnpm ERR! errno -13npm ERR! Error: EACCES: permission denied, access '/usr/local/lib/node_modules'npm ERR! [Error: EACCES: permission denied, access '/usr/local/lib/node_modules'] {npm ERR! errno: -13,npm ERR! code: 'EACCES',npm ERR! syscall: 'access',npm ERR! path: '/usr/local/lib/node_modules'npm ERR! }装置实现后,能够应用上面的命令查看应用办法: ...

July 15, 2022 · 2 min · jiezi

关于node.js:如何使用-Nodejs-MongoDB-开发-RESTful-API-接口Nodejs-Express

本文完整版:《后端实战手把手教你写文件上传接口:如何应用 Node.js + MongoDB 开发 RESTful API 接口(Node.js + Express + MongoDB)》 本教程手把手教你搭建一套后端文件上传 API 接口,它应用 Node.js + Express + MongoDB 构建的后端服务。本文详细描述通过 Node.js 与数据库通信。整个服务搭建起来后,咱们应用 Postman 对整个后端服务进行测试。 本教程每段代码我都亲手测过,保障百分百没有谬误,请关上你的 terminal 追随本教程一起操作,从这里开始,成为一名后端工程师。 全栈实战教程: Vue + Node.js+Expres+MySQL 开发「待办清单」APPVue + Axios + Node.js + Express 搭建带预览的「上传图片」治理后盾Vue + Axios + Node.js + Express 搭建「文件上传」治理后盾React + Nodejs 搭建带预览的「上传图片/预览」治理后盾React + Axios + Node.js + Express 搭建「文件上传」治理后盾后端实战教程: 应用 Node.js + MySQL 开发 RESTful API 接口(Node.js + Express + Sequelize + MySQL)应用 Node.js + MongoDB 开发 RESTful API 接口(Node.js + Express + MongoDB)如果你正在搭建后盾管理工具,又不想解决前端问题,举荐应用卡拉云,卡拉云是新一代低代码开发工具,可一键接入常见数据库及 API ,无需懂前端,仅需拖拽即可疾速搭建属于你本人的后盾管理工具,一周工作量缩减至一天,详见本文文末。 ...

July 12, 2022 · 4 min · jiezi

关于node.js:如何使用Nodejs开发RESTful-API接口NodejsExpressSequelizeMySQL

本教程手把手教你搭建一套应用 Node.js + Express + Sequelize + MySQL 构建的后端服务,详细描述通过 Node.js 与数据库通信。整个服务搭建起来后,咱们应用 Postman 对整个后端服务进行测试。本教程每段代码我都亲手测过,保障百分百没有谬误,请关上你的 terminal 追随本教程一起操作,从这里开始,成为一名后端工程师。 全栈实战教程: Vue + Node.js+Expres+MySQL 开发「待办清单」APPVue + Axios + Node.js + Express 搭建带预览的「上传图片」治理后盾Vue + Axios + Node.js + Express 搭建「文件上传」治理后盾React + Nodejs 搭建带预览的「上传图片/预览」治理后盾React + Axios + Node.js + Express 搭建「文件上传」治理后盾后端实战教程: 应用 Node.js + MySQL 开发 RESTful API 接口(Node.js + Express + Sequelize + MySQL)应用 Node.js + MongoDB 开发 RESTful API 接口(Node.js + Express + MongoDB)如果你正在搭建后盾管理工具,又不想解决前端问题,举荐应用卡拉云,卡拉云是新一代低代码开发工具,可一键接入常见数据库及 API ,无需懂前端,仅需拖拽即可疾速搭建属于你本人的后盾管理工具,一周工作量缩减至一天,详见本文文末。 ...

July 11, 2022 · 5 min · jiezi

关于node.js:React-Nodejs-全栈实战教程-手把手教你搭建文件上传管理后台

本教程手把手率领大家搭建一套通过 React + Node.js + Mongodb 上传文件的后盾零碎,只有你追随本教程一步步走,肯定能很好的了解整个前后端上传文件的代码逻辑。前端咱们应用 Reactjs + Axios 来搭建前端上传文件利用,后端咱们应用 Node.js + Express + Multer + Mongodb 来搭建后端上传文件解决利用。 当然,本教程还会教给大家如何写一个能够限度上传文件大小、有百分比进度条、可报错、可显示服务器上文件列表、可点击下载文件的前端操作界面。 最初实现的上传文件工具后盾如下图,追随本教学习,你也能够搭建进去。 全栈实战教程: Vue + Node.js+Expres+MySQL 开发「待办清单」APPVue + Axios + Node.js + Express 搭建带预览的「上传图片」治理后盾Vue + Axios + Node.js + Express 搭建「文件上传」治理后盾React + Nodejs 搭建带预览的「上传图片/预览」治理后盾React + Axios + Node.js + Express 搭建「文件上传」治理后盾后端实战教程: 应用 Node.js + MySQL 开发 RESTful API 接口(Node.js + Express + Sequelize + MySQL)应用 Node.js + MongoDB 开发 RESTful API 接口(Node.js + Express + MongoDB)如果你正在搭建后盾管理工具,又不想解决前端问题,举荐应用卡拉云,卡拉云是新一代低代码开发工具,可一键接入常见数据库及 API ,无需懂前端,仅需拖拽即可疾速搭建属于你本人的后盾管理工具,一周工作量缩减至一天,详见本文文末。 ...

July 11, 2022 · 7 min · jiezi

关于node.js:Nodejs工程师养成计划完整无密某课

download:Node.js工程师养成打算残缺无密某课程序员如何利用技术能力变现 本质上来说,程序员是手艺人,有手艺的人就能做出别人做不进去的货色,而付费也是一件很天然的事了。那么,这个问题就成了,如何让自己的“手艺”更为值钱的问题了。千里之行,积于跬步 任何一件胜利的小事,都是通过一个一个的小胜利达到的。所以,你得确保你有一个一个的小胜利。具体说来,首先,你得让自己身边的人有求于你,或是向别人推荐你。这就需要你能够管制大多数人不能管制的技能或技术,需要你更多地学习,并要有更多的别人没有的经验和经历。一旦你身边的人开始有求于你,或是向别人推荐你,你就会被内部的人留意到,于是其他人就会付费来获取你的帮助。而一旦你的帮忙有成果的话,就会产生效益,无论是经济效益还是社会效益,都会为你开拓更大的空间。你也会因为这样的正向反应而鼓励自己去学习和钻研更多的货色,从而失去一个正向的循环。而且这个正向循环,一旦开始就停不下来了。 关注有价值的货色什么是有价值的货色?价值其实是受供需关系影响的,供大于求,就没什么价值,供不应求,就有价值。这意味着你不只有看到市场,还要看到技术的趋势,能够分辨出什么是支流技术,什么是过渡式的技术。当你比别人有更好的嗅觉时,你就能起动得更快,也就比别人有 先发劣势。对于市场需求。要看清市场,就需要看看各个公司在做什么,他们的难题是什么。简略来说,现在的每家公司无论大小都缺人。是真的缺人吗?中国是人口大国,不缺写代码搬砖的,真正缺的是有能力能够解决技术难题的人,能够提高团队人效的人。所以,从这些方面思考,你会知道哪些技能才是真正的“供不应求”,这样可能让你更有价值。 对于技术趋势。要看清技术趋势,你需要了解历史,就像一个球静止一样,你要知道这个球未来静止的地方,是需要观察球的已经实现静止的轨迹才知道的。因此,了解技术发展轨迹是一件很重要的事。要看一个新的技术是否适应技术发展趋势,你需要将一些老技术的本质吃得很透。因此,在学习技术的过程肯定要多问自己两个问题:“1. 这个技术解决什么问题?为什么别的同类技术做不到?2. 为什么是这样解决的?有没有更好的形式?”另外,还有一个简略的判断方法,如果一个新的技术适应技术发展趋势,那么在这个新的技术出现时,前面肯定会有大型的商业公司反对,这类公司反对得越多,就说明你越需要关注。 找到能体现价值的地方在一家高速发展的公司中,技术人员的价值可能达到最大化。试想,在一家大公司中,技术架构和业务已经定型,基本上没有什么太多的事可能做的。而且对于已经发展起来的大公司来说,经常稳固的重要性超过了翻新。此外,大公司的高级技术人员很多,多你一个不多,少你一个不少,所以你的价值很难被体现进去。而刚起步的公司,业务还没有跑顺,公司的次要精力会放在业务拓展上,这个时候也不太需要高精尖的技术,所以,技术人员的价值也体现不进去。只有那些在高速发展的公司,技术人员的价值才能被最大化地体现进去。比较好的成长路径是,先进入大公司学习大公司的技术和胜利的经验方法,而后找到高速成长的公司,可能实现自己更多的价值。当然,这里并不排除在大公司中找到高速发展的地方。动手能力很重要 成为一个手艺人,动手能力是很重要的,因为在解决任何一个具体问题的时候,有没有动手能力就成为了要害。这也是我一直在写代码的原因,代码里全是细节,细节是魔鬼,只有了解了细节,你才能提出更好或是更靠谱的并可能落地的解决打算。而不是一些抽象和含混的货色。这太重要了。 关注技术付费点技术付费点基本体现在两个地方,一个是,能帮别人“挣钱”的地方;另一个是,能帮别人“省钱”的地方。也就是说,能够帮助别人更流利地挣钱,或是能够帮助别人提高效率,能俭约更多的成本,越间接越好。而且这个技术或解决打算最好还是大多数人做不到的。晋升自己的能力和经历 付费的前提是信赖,只有你晋升自己的能力和经历后,他人才会对你有肯定的信赖,才会感觉你靠谱,才会给你机会。而这个信赖需要用你的能力和经历来填补。比如,你是一个很出名的开源软件的核心开发人员,或是你是某出名公司核心我的项目的核心开发人员,等等。找到有价值的信息源 信息社会,如果你比别人有更好的信息源,那么你就可能比别人成长得更快。对于技术人员来说,咱们知道,几乎所有的技术都源自东方世界,所以,你应该走到信息的源头去。如果你的信息来自朋友圈、微博、知乎、百度或是今日头条,那么你完蛋了。因为这些渠道有价值的信息不多,有养分的可能只有 1%,而为了这 1%,你需要读完 99% 的信息,太不划算了。那么如何找到这些信息源呢?用好 Google 就是一个要害,比如你在 Google 搜索引擎里输出“XXX Best Practice”,或是“Best programming resource”……你就会找到很多。而用好这个更好的信息源需要你的英文能力,因此不断晋升英文能力很要害。 输入观点和价值观真正微小的公司或是产品都是要输入价值观的。只有输入了更先进的价值观,才会获得真正的影响力。然而,你要能输入观点和价值观,并不是一件容易的事,这需要你的积累和经历,而不是一朝之功,需要长期积累。因此,如果想要让你的技能变现,这本质上是一个厚积薄发的过程。

July 11, 2022 · 1 min · jiezi

关于node.js:NodeJS错误处理

前言最近在公司的Koa.js我的项目中遇到一个问题,应用thrift库创立一个connection,在接口中应用该连贯的client来发送申请,后果抛错连贯失败且中断了程序的执行,用try/catch无奈捕捉到该谬误。遂查看创立连贯的源码,发现Connection构造函数中有如下代码: var Connection = exports.Connection = function(stream, options) { var self = this; EventEmitter.call(this); this.connection = stream; // ...其余代码 this.connection.addListener("error", function(err) { // Only emit the error if no-one else is listening on the connection // or if someone is listening on us, because Node turns unhandled // 'error' events into exceptions. if (self.connection.listeners('error').length === 1 || self.listeners('error').length > 0) { self.emit("error", err); } }); // ...其余代码}正文翻译:只有在没有人监听连贯或有人监听咱们(this)时才收回谬误,因为 Node 会将未解决的“谬误”事件变成异样。 ...

July 9, 2022 · 2 min · jiezi

关于node.js:SpringBoot网上书城的设计与实现源码论文二稿ppt开题报告中期检查代码讲解视频包安装

项目名称SSM框架特产销售网站设计与开发源码 视频成果SpringBoot网上书城的设计与实现源码+文档 SpringBoot网上书城的设计与实现源码 零碎阐明小说浏览包含两局部:前景和背景。前端性能五个模块:小说分类浏览、用户注册、在线留言、小说查问和章节浏览。后盾包含八个模块:统计分析、用户治理、分类管理、小说治理、章节治理、音讯治理和管理员治理。 用户治理包含系统管理、明码批改和注册治理。小说治理包含小说信息增加、小说类别增加、小说信息查问和小说类别查问。站内新闻包含站内新闻增加和站内新闻查问。用户注册意味着用户能够在网站上注册。注册后,用户能够增加书签,不便用户治理本人喜爱的小说。 如下图3-1所示,这是书店零碎的性能结构图,形容了零碎整体性能的个别信息。 环境须要1.运行环境:最好是java jdk 1.8,咱们在这个平台上运行的。其余版本实践上也能够。2.IDE环境:IDEA,Eclipse,Myeclipse都能够。举荐IDEA;3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可4.硬件环境:windows 7/8/10 1G内存以上;或者 Mac OS; 5.数据库:MySql 5.7版本;6.是否Maven我的项目:否; 技术栈 后端:Spring+SpringMVC+Mybatis前端:JSP+CSS+JavaScript+jQuery应用阐明 应用Navicat或者其它工具,在mysql中创立对应名称的数据库,并导入我的项目的sql文件;应用IDEA/Eclipse/MyEclipse导入我的项目,Eclipse/MyEclipse导入时,若为maven我的项目请抉择maven;若为maven我的项目,导入胜利后请执行maven clean;maven install命令,而后运行;将我的项目中springmvc-servlet.xml配置文件中的数据库配置改为本人的配置;运行我的项目,在浏览器中输出http://localhost:8080/ 登录运行截图  用户管理控制层:package com.houserss.controller; import javax.servlet.http.HttpSession; import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody; import com.houserss.common.Const;import com.houserss.common.Const.Role;import com.houserss.common.ServerResponse;import com.houserss.pojo.User;import com.houserss.service.IUserService;import com.houserss.service.impl.UserServiceImpl;import com.houserss.util.MD5Util;import com.houserss.util.TimeUtils;import com.houserss.vo.DeleteHouseVo;import com.houserss.vo.PageInfoVo; /** Created by admin */@Controller@RequestMapping("/user/")public class UserController { @Autowiredprivate IUserService iUserService;/** * 用户登录 * @param username * @param password * @param session * @return */@RequestMapping(value = "login.do",method = RequestMethod.POST)@ResponseBodypublic ServerResponse<User> login(User user,String uvcode, HttpSession session){ String code = (String)session.getAttribute("validationCode"); if(StringUtils.isNotBlank(code)) { if(!code.equalsIgnoreCase(uvcode)) { return ServerResponse.createByErrorMessage("验证码不正确"); } } ServerResponse<User> response = iUserService.login(user.getUsername(),user.getPassword()); if(response.isSuccess()){ session.setAttribute(Const.CURRENT_USER,response.getData()); } return response;}} ...

July 2, 2022 · 4 min · jiezi

关于node.js:CabloyJS-422重磅推出弹出式页面交互风格

降级阐明咱们晓得CabloyJS提供了pc=mobile+pad自适应布局机制,能够通过一套代码同时适配mobile端和pc端。基本思路就是优先适配mobile端,而后再把mobile端的交互体验带入pc端。因而,pc端能够看作是许多mobile尺寸和pad尺寸页面组件的组合。在旧版本中,这些页面组件就像大大小小的手机和平板顺次向右开展,能够称作展开式交互格调 新版本CabloyJS 4.22提供了弹出式交互格调。这样,用户能够依据pc电脑的尺寸大小和集体爱好,在这两个交互格调中随时切换 对于pc=mobile+pad自适应布局机制的详细信息,请参见文档:自适应布局:pc = mobile + pad意义CabloyJS 4.22的公布,重磅引入弹出式页面交互格调,是及其次要的里程碑,将CabloyJS推入一个新的倒退阶段 是认为记 2022年6月30日 预览1. PC端(展开式) 2. PC端(弹出式) 3. Mobile端 演示站点间接浏览CabloyJS的演示站点,减少更直观的理性认知 体验CabloyJS应答大型项目的三驾马车:套件、模块、App利用体验不同凡响的pc=mobile+pad自适应布局格调,强烈推荐:别离用PC和Mobile独自体验演示站点。此言不虚,请您品鉴!!!演示站点:https://test.cabloy.com/演示站点的二维码:相干链接文档: https://cabloy.com/GitHub: https://github.com/zhennann/c...

June 30, 2022 · 1 min · jiezi

关于node.js:Nodejs工程师养成计划某课附资料

download:Node.js工程师养成打算【某课】万物皆可柯里化的 Ramda.js咱们前段时间写过好几篇对于 RxJS 的文章,RxJS api 操作符理解起来确实比较简单,RxJS 是函数式编程中的 lodash 库,它消除了“时序”而带来的干扰,它中心思想是:函数式 + 响应式。本篇, 要讲的不是 RxJS,而是另外一个函数式编程库 Ramda.js ,它同样也可能与 loadsh 对比理解,不过它的设计思路又不同了,它最大的个性是:所有函数都可能柯里化传参!以此来践行函数式编程思维。 往下看,前面咱们就能明确:Ramda 所有 Api 都能柯里化的意义所在。Function first,Data last在 lodash 中,咱们是这样写的,var square = n => n * n;_.map([4, 8], square) 参数在前,执行函数在后。而在 Ramda 中,强调:函数在前,参数在后。这样做有什么好处呢?就是为了更好实现:柯里化。柯里化只需要参数一个一个的在后追加var R = require('ramda');R.map(square, [4, 8]) // 同等于 var R = require('ramda');R.map(square)([4, 8]) 再举个栗子:var R = require('ramda'); const odd = x => x%2 === 1const data = [3, 5, 6]; R.filter(odd, data); // [3, 5] ...

June 24, 2022 · 2 min · jiezi

关于node.js:Nodejs工程师养成计划某课超清无密

download:Node.js工程师养成打算【某课】章节目录: 第1章 课程介绍 试看1 节 | 15分钟把握课程根本内容,理解课程设计起因,把握课程阶段性指标。收起列表视频:1-1 课程导学 (14:33)试看第2章 Node 原生开发根底入门7 节 | 76分钟把握 Node 开发的根本逻辑,实现本地开发环境搭建,了解模块化开发等相干内容,可能应用Node 运行 JavaScript 逻辑代码,为之后的我的项目开发建设常识储备。收起列表视频:2-1 Node.js编程根底概要 (09:54)视频:2-2 本地环境搭建与根底入门 (08:07)视频:2-3 文件操作与模块化的概念 (19:04)视频:2-4 JavaScript模块化开发 (20:43)视频:2-5 npm包管理器 (09:45)视频:2-6 第三方工具包的应用 (06:04)视频:2-7 总结_ (01:34)第3章 Node 脚手架篇 – 打造本人的脚手架工具10 节 | 94分钟使用 Node 基础知识,实现脚手架我的项目,打造一个本人的脚手架工具,为后续web我的项目的构建打基础,同时本我的项目中会退出更深层次的 Node 相干常识,实现对Node 自身相干常识的全面构建收起列表视频:3-1 自定义脚手架概述 (05:16)视频:3-2 创立自定义全局指令 (07:03)视频:3-3 应用commander解决help选项 (09:59)视频:3-4 解决自定义指令选线 (08:09)视频:3-5 逻辑代码模块化拆分 (10:00)视频:3-6 命令行问答交互 (12:01)视频:3-7 下载近程仓库模板代码 (18:40)视频:3-8 下载期待提醒交互 (12:41)视频:3-9 命令行款式输入 (06:56)视频:3-10 自定义脚手架我的项目总结 (02:37)第4章 Node 原生实战篇 – 我的项目基建 – 原生Node 开发Web 服务器7 节 | 76分钟以实现我的项目开发为主导思路,应用原生 Node 技术解说 HTTP 利用相干的内容,构建前后端通信根本逻辑,实现Web我的项目开发的根本通信架构,同时,引出应用框架进行我的项目的逻辑和意义。收起列表视频:4-1 Node原生开发Web服务器介绍 (10:43)视频:4-2 应用Node创立HTTP服务器 (13:25)视频:4-3 服务器响应不同数据类型 (15:31)视频:4-4 HTTP的不同申请办法解决 (10:08)视频:4-5 接管并解决POST音讯数据 (09:48)视频:4-6 服务器代码模块化拆分 (09:54)视频:4-7 Node开发web服务器-问题与总结 (06:21)第5章 Node 框架篇 – Express 框架重构我的项目逻辑8 节 | 79分钟实现 Express 框架的介绍及根本应用,对上一章原生 Node 构建的我的项目基本功能,应用框架进行重构,实现我的项目开发的基本操作逻辑,同时,应用后面曾经写好的脚手架,进行我的项目的初始化构建。收起列表视频:5-1 Express框架介绍 (05:33)视频:5-2 Express我的项目构建 (07:59)视频:5-3 Express框架根本应用 (04:21)视频:5-4 Express治理用户数据信息 (13:52)视频:5-5 解决客户端 Post 申请数据 (09:24)视频:5-6 增加用户信息到db文件 (20:25)视频:5-7 批改用户信息 (14:33)视频:5-8 Express根底利用总计与操作JSON的问题 (02:44)第6章 Node 框架实战篇 – 我的项目数据长久化存储8 节 | 97分钟以最根底的用户注册性能为切入点,引入数据长久化存储相干内容,应用 Node 操作数据长久化接口,实现我的项目所需的数据库设计,为我的项目登录性能做铺垫。收起列表视频:6-1 我的项目数据长久化存储MongoDB (07:15)视频:6-2 在不同的操作系统中装置MongoDB (18:34)视频:6-3 MongoShell执行环境与客户端 (07:43)视频:6-4 MongoDB的根底概念 (17:11)视频:6-5 MongDB根本增删改查操作 (13:47)视频:6-6 应用Node链接MongoDB (08:20)视频:6-7 应用Node进行增删改查操纵 (13:26)视频:6-8 总结与回顾-应用脚手架工具创立我的项目基础架构 (10:26)第7章 Node框架实战篇 – Express 中间件与RESTful API 接口标准 15 节 | 259分钟以登录性能为主,引入 JWT 身份验证机制,引入 Express 中重要的中间件相干内容,同时,引入RESTful API 接口标准,实现前后端交互中的接口设计逻辑。收起列表视频:7-1 Express中间件的概念与根本利用 (14:38)视频:7-2 不同中间件类别的应用形式-1 (11:40)视频:7-3 不同中间件类别的应用形式-2 (10:47)视频:7-4 Express路由与响应办法 (18:25)视频:7-5 我的项目根底设计搭建优化 (17:30)视频:7-6 数据处理模块-mongoose (17:48)视频:7-7 用户注册数据入库 (12:05)视频:7-8 用户注册的明码加密问题 (15:59)视频:7-9 客户端提交数据安全校验.mp4 (26:45)视频:7-10 数据唯一性验证 (10:13)视频:7-11 RESTfulAPI接口设计规范 (26:38)视频:7-12 用户登录信息比照 (15:17)视频:7-13 JWT用户身份认证 (16:25)视频:7-14 用户登录认证与接口鉴权 (30:15)视频:7-15 逻辑代码修理与中间件接口标准总结 (13:38)第8章 Node框架实战篇 – 文件上传与治理实现自媒体频道的创立、关注、勾销关注等性能,同时实现对本人频道视频的上传、上架、下架、删除等操作。第9章 Node框架实战篇 – Redis 缓存实现自媒体平台的用户交互相干性能,同时引出Redis缓存的相干常识,实现视频举荐等相干性能。第10章 Node框架实战篇 – 云服务器与 Nginx 代理我的项目功能模块根本实现,进行我的项目上线部署阶段,实现对域名解析、服务器运维、以及Nginx代理等相干内容。第11章 koa框架重构篇 – Koa疾速入门Koa 框架的根本应用,为我的项目重构做基本知识储备。第12章 koa框架重构篇 – Koa框架我的项目重构应用 Koa 框架,对自媒体我的项目进行重构,实现我的项目根本功能模块,同时对 Express 与 Koa 框架进行比照总结。第13章 Egg框架重构篇 – Egg.js 疾速入门Egg.js 框架的根本应用,为我的项目重构做基本知识储备。第14章 Egg框架重构篇 – Egg.js 框架我的项目重构应用egg框架,对自媒体我的项目进行重构,实现我的项目根本功能模块,同时对 Express 与 egg框架进行比照总结。第15章 Nest框架利用根底与实战介绍 Nest 框架的设计哲学,把握根本的装置与利用,了解控制器、路由、中间件等外围性能,可能联合 TypeScript 进行我的项目开发。第16章 课程回归与总结课程回归与总结。本课程继续更新中 ...

June 23, 2022 · 2 min · jiezi

关于node.js:用docker部署nodejs项目CENTOS7

当初容器化技术这么炽热,作为学习,这篇文章就和大家聊一聊,我是如何应用docker把一个nodejs我的项目部署上线的。废话不多说,上面开始进入正题: 一、装置 Dockercentos7装置docker请看这篇文章:https://blog.csdn.net/cbh1987... 首先在服务器上安装 Docker,参照官网极简教程,很快便能装置好,搭建 Docker 环境。(若已装置,则跳过此步骤) 要晓得是否装置胜利,执行以下命令,呈现版本号,代表装置胜利。 docker -v 二、创立 Dockerfile 文件Dockerfile 是一个用来构建镜像的文本文件,文本内容蕴含了一条条构建镜像所需的指令和阐明。Docker 可能读取 Dockerfile 的指定进行主动构建容器。 接着将你的node我的项目改名成app目录,上传到你的centos7服务器。而后新建一个内容是上面代码的Dockerfile文件。 我用的nodejs我的项目是这个地址:https://gitee.com/cdk8s/cdk8s... 留神:Dockerfile文件要在你的我的项目根目录外面,如下图: 在我的项目根目录新建 Dockerfile,执行命令: touch Dockerfile 这个是csdn博客作者他写入的参考代码: FROM mhart/alpine-node:9 WORKDIR /appCOPY . /app RUN rm -f package-lock.json \; rm -rf .idea \; rm -rf node_modules \; npm config set registry "https://registry.npm.taobao.org/" \&& npm config set unsafe-perm true && npm install RUN npm install pm2 -g EXPOSE 3000CMD ["pm2-runtime", "start", "app.js", "-n", "uni-docker"]这个文件蕴含了以下命令: ...

June 16, 2022 · 1 min · jiezi

关于node.js:Nodejs工程师养成计划某课

download:Node.js工程师养成打算【某课】SpringBoot整合Druid数据源一、SpringBoot 整合DruidSprintBoot 默认使用的是 HikariDataSource数据源,这次整合一个第三方的数据源 Druid ,它是阿里开发的一款开源的数据源,被很多人认为是Java语言中最好的数据库连接池,因为 Druid 能够提供弱小的一整套监控和扩大功能。默认情况下,sprintboot使用hikaridatasource数据源。这一次,集成了第三方数据源Druid。它是阿里巴巴开发的开源数据源,许多人认为它是Java语言中最好的数据库连接池,因为Druid可能提供一组弱小的监控和扩大功能。1、在创建SpringBoot我的项目的时候,在pom.xml maven中增加依赖: org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-jdbc mysql mysql-connector-java 5.1.47 log4j log4j 1.2.17 com.alibaba druid 复制代码注意:druid 依赖 log4j 的日志jar包,然而 SpringBoot 默认使用的是 slf4j+logback,所以导入log4j的jar包即可。2、在 application.yml(或aproperties)中增加相应的配置: server: port: 80 # 数据库连接信息spring: datasource: username: rootpassword: 123456url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMTdriver-class-name: com.mysql.cj.jdbc.Driver # com.mysql.jdbc.Driver使用 Druid 数据源type: com.alibaba.druid.pool.DruidDataSource复制代码3、 log4j.properties 配置文件:log4j.rootLogger = debug,stdout, Dlog4j.appender.stdout = org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.Target = System.outlog4j.appender.stdout.Threshold = INFOlog4j.appender.stdout.layout = org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern=%d %p %m%nlog4j.appender.D = org.apache.log4j.DailyRollingFileAppenderlog4j.appender.D.File = ./log4j.loglog4j.appender.D.Append = truelog4j.appender.D.Threshold = DEBUGlog4j.appender.D.layout = org.apache.log4j.PatternLayoutlog4j.appender.D.layout.ConversionPattern=%d %p %m%n复制代码4、在运行测试方法,查看数据源public class SpringbootdemoApplicationTests { ...

June 14, 2022 · 1 min · jiezi

关于node.js:Nodejs工程师养成计划完整无密某课

download:Node.js工程师养成打算残缺无密通过实例深入理解sync.Map的工作原理一. 原生map的“先天不足”对于已经初始化了的原生map,咱们可能尽情地对其进行并发读:// github.com/bigwhite/experiments/inside-syncmap/concurrent_builtin_map_read.go package main import ( "fmt""math/rand""sync") func main() { var wg sync.WaitGroupvar m = make(map[int]int, 100)for i := 0; i < 100; i++ { m[i] = i}wg.Add(10)for i := 0; i < 10; i++ { // 并发读 go func(i int) { for j := 0; j < 100; j++ { n := rand.Intn(100) fmt.Printf("goroutine[%d] read m[%d]: %d\n", i, n, m[n]) } wg.Done() }(i)}wg.Wait()} 复制代码但原生map一个最大的问题就是不反对多goroutine并发写。Go runtime内置对原生map并发写的检测,一旦检测到就会以panic的形式阻止程序持续运行,比如上面这个例子:// github.com/bigwhite/experiments/inside-syncmap/concurrent_builtin_map_write.go package main import ( ...

June 13, 2022 · 3 min · jiezi

关于node.js:Node-Express

Express是什么Express 是一个放弃最小规模的灵便的 Node.js Web 利用程序开发框架,为 Web 和挪动应用程序提供一组弱小的性能。应用您所抉择的各种 HTTP 实用工具和中间件,疾速不便地创立弱小的 API。Express 提供精简的根本 Web 应用程序性能,而不会暗藏您理解和青眼的 Node.js 性能。中文地址:https://www.expressjs.com.cn/应用下载npm i express --save构建指定文件// index.js 举例,另外 `.js` 能够省略node index.js批改完代码主动构建nodemon: 第三方插件,就是为了解决 node 每次批改实现当前都须要从新构建的问题下载:npm i nodemon -g,这种工具类的最好都是全局装置应用形式:nodemon index.jsAPIhello worldvar express = require('express')// 创立服务器,相当于http.createServervar app = express();app.get('/', function(req,res) { res.send('hello')})app.listen(9527,function() { console.log('app is running at port 9527')})根本路由// getapp.get('/', function(req,res) { res.send('get')})// postapp.post('/', function(req,res) { res.send('post')})动态服务// 公开指定目录// 只有这样做了,你就能够间接通过/public/xx的形式拜访public下的所有资源了app.use('/public',express.static('./public')) // 通过localhost:9527/public/index.html// 还能够省略第一个参数,然而省略第一个参数的时候,拜访形式中也要省略掉对应的门路app.use(express.static('./static')) // 拜访形式变成了localhost:9527/index.html// 还有一种是给公开目录取别名app.use('/abc',express.static('./pages')) // 通过localhost:9527/abc/index.htmlExpress中应用art-template装置: npm i --save art-templatenpm i --save express-art-template配置: ...

June 9, 2022 · 1 min · jiezi

关于node.js:如何用pkg打包nodejs可执行文件

应用pkg能够将Node.js我的项目打包为可执行文件,甚至能够在未装置Node.js的设施上运行。 试验环境 操作系统:windowsnode版本: 16.14.2 操作过程 下载PKG咱们能够抉择全局装置,在任意目录执行: $ npm install -g pkg打包程序先写一个简略的程序,比方server.js内容 const express = require('express');const app = express();app.get('/', (req, res) => { res.send('Hello World!');});app.listen(3000, () => { console.log('Express web app on localhost:3000');});进入nodejs我的项目根目录,执行如下命令 $ pkg server.js第一次报错 这时候会报错 $ pkg server.js> pkg@5.6.0> Targets not specified. Assuming: node16-linux-x64, node16-macos-x64, node16-win-x64> Fetching base Node.js binaries to PKG_CACHE_PATH fetched-v16.14.2-linux-x64 [ ] 0%> Not found in remote cache: {"tag":"v3.3","name":"node-v16.14.2-linux-x64"}> Building base binary from source: built-v16.14.2-linux-x64> Error! Not able to build for 'linux' here, only for 'win'粗心是,以后环境只反对编译为windows零碎的可执行文件,也就是win ...

June 9, 2022 · 1 min · jiezi

关于node.js:nodejs快速生成ca证书和ssl证书

npm install mkcert -gmkcert create-ca --organization "ShanYou CA" --country-code "CN" --state ="HeBei" --locality "BaoDing" --validity 36500 --key ca.key --cert ca.crtmkcert create-cert --validity "3650" --key "server.key" --cert "server.crt"

May 31, 2022 · 1 min · jiezi