这是我参与「第四届青训营 」笔记创作活动的第二天
01 Node.js应用场景why
1.前端工程化的这些工具基本上需要Node.js去 实现服务端的能力、在浏览器之外跑js代码、调用操作系统的api完成一些任务 等。也是nodejs的出现加速了这些工具的催生。
新一代构建(打包)工具rollup/parcel/esbuild
打包 代码压缩 语法转换 其他语言(go\rust\数据库工具)
2.nodejs可以做到其他传统后端语言可以做到的事。Vercel是next.js背后的公司。与前端开发结合的web服务端应用有市场。
SSR:服务端渲染
拓:JS几大常用的包管理工具对比:NPM、NRM、CNPM、YARN
nrm 和 nvm
nrm (npm registry manager)是npm的镜像源管理工具nvm (node version manager)是nodejs的版本管理工具
3.electron结合了web和nodejs实现跨端桌面应用。nodejs有非常多的基于electron的方案。
另外还有BFF、SSR(这是微服务层面的内容)。BFF:谁需要接口,谁去开发,核心业务逻辑在后端,接口拼接和由端的需要构建api时由端自己构建,后端和前端不再需要紧密结合,在某几个接口合并为一个接口或裁剪一些不需要的数据(避免传输)。服务端渲染SSR应用:例子modern.js
02 Node.js运行时结构what
社区的npm代码:acron node-inspect调试 npm
通过npm去安装的外部的包也属于用户代码。
libuv封装不同操作系统api并提供统一的api、提供nodejs最核心的root、提供跨平台的io操作(面试问题)调用异步的api时,触发异步调用,把像读取文件[fs.readFile()]的异步操作交给libuv的线程池去做
zlib 解压、压缩
c-aresDNS查询的库
llhttp http协议解析
nghttp2 http2的库
OpenSSL网络层面的加密、解密
诊断调试工具是v8自带的,nodejs很多特点是基于v8实现的。nodejs在解释性语言里面执行效率高,很大成度是因为v8。
用node-fetch发起请求时:通过npm安装node-fetch模块,到用户代码调用node-fetch模块,都是js代码所以到v8执行。node-fetch在nodejs这块底层调用http模块,在Node.js Core(JavaScript)里。http模块再调用更底层的Core(c++),再调用llhttp(序列化、反序列化),libuv创建http连接,把数据发给远端。反过来是一样的,远端传过来一些数据以后,libuv->llhttp->core(js)->用户代码。
跨平台这里socket是做进程间通信。
异步IO相比于多线程模型,内存占用会更少。因为阻塞线程的过程中不能把内存给释放掉。如果有其他类似操作的话,它们同样也会占用这些内存。js有垃圾回收,就有更多的内存可用,gc时间减少,不需要频繁做gc减少内存空间。(不太理解内存占用更少)
单线程,指,只有主线程(js线程)是单线程。用工具看nodejs进程里有哪些线程,能有好多线程,其中有libuv提供的四个线程(默认),即libuv里的线程池(uv线程池)。比如,读文件的场景,大多数操作系统读取文件操作都是同步的系统操作,nodejs为了不阻塞后面的操作,就会把读取操作放到libuv线程池里进行,这样主线程js就可以做更多事情。(对cpu消耗比较高的底层操作也会交给线程池去做,比如加密解密)。延时敏感不适合用单线程模型。
03 编写HTTP Server how
这部分代码存于vue/http_server
1 编写http server+client,收发GET、POST请求
--前端的http GET server给我的http请求返回数据
commonjs 和 esm(课后)
--期望用户给我传入一个json数据,用post method,从数据里把msg(message)取出来,然后返回给客户
--上一个例子因为直接通过浏览器访问的,实际上没有给server传json数据。通过http client发送post请求给服务端,因为get请求不允许带上http body。
--回调函数:很多场景下可直接用,不易维护、管理。所以下面重构可以方便维护(把callback封装成promise函数,使回调函数触发时机明确)
协程(课外)
util.promisify是在node.js 8.x版本中新增的一个工具(课外,util模块),避免promise的重复封装 链接:www.php.cn/js-tutorial…
util.promisify遵循nodejs的约定(平时多注意nodejs提供的api):返回的第一个参数(heller字段),如果前面异步操作出现问题,通过这个发现;在第二、三个参数再把实际数据传给用户。
异步IO中实现主要包含提交请求和处理结果两个阶段,可能在异步IO的过程中会有异常。 nodejs有一个约定,将异常作为回调函数的第一个参数传回,如果为空值,则表明异步调用没有异常抛出,因此写回调函数的时候,首先要判断其第一个参数是否为空,再执行后面的操作。 链接:www.jianshu.com/p/591dc8af1…
2 编写静态文件服务器
拿到静态文件服务器上对应的文件路径,把文件读取出来,把具体文件内容返回请求。
(面试问题)stream风格的api有什么好处?内部做过处理,可以尽可能少地占用内存空间。 像例子里需要把文件内容传给前端,但数据在不同端之间传输有速率问题。fs把整个文件读取下来传给服务器,在这个进程中给文件分配内存空间。如果静态文件服务器有个非常大的文件,而服务部署在较小的容器,不得不申请更高规格的容器满足需求(毕竟还有额外占用内存空间的东西存在)。用stream好处是把所有数据储存到stream,按需返回定义的client。client读取速率没那么高时,server也不用把整个文件存到内存里。(stream里数据存哪有区别吗?)
3 编写React SSR服务
前端工程化、服务端渲染等例子不是很依赖html模板引擎,很少写html代码,生成html的逻辑放在js里,只要能运行js代码就能知道返回的是什么html代码。
相比于SPA单页面应用(即不考虑服务端渲染,所有逻辑类似于vue、react去把大部分html写到js里,问题:需要等所有js代码加载好后才开始给用户返回数据,首屏慢,不利于SEO搜索引擎优化)
缺点:
服务端应用的qps低:1.字符串拼接的逻辑 2.服务端渲染即在服务端执行js代码,渲染时请求更长。
难编写。需要考虑服务端和前端。
(课外)SPA SEO SSR三者区别t.zoukankan.com/lml-lml-p-9…
(课外)tps和qps区别和理解?
安装react包:npm i react react-dom
SSR难点:
打包 用commonjs的require语句然后webpack动态加载,但是在服务端这样写没用的,需要绕过css和图片等的处理。约定:未来不用这种方式加载css代码
拉数据然后根据服务端返回的数据去渲染,拉数据时机?react生命周期的后面,比如componentDidMount及后面去执行,在刚才ReactDOMServer.renderToString时这个不会触发,避免服务端渲染时拉数据操作fetch被执行。
副作用:一些数据需要挂载到全局windows上,nodejs的一些配置把global替换成window,虽然正常运行,但每次都需要从window拿数据做渲染
4 调试
node --inspect server_ssr.js
进入devtools://devtools/bundled/js_app.html?experiments=true&v8only=true&ws=127.0.0.1:9229/a5956950-a974-4c27-8233-526fc5be8417
然后可以进行各种操作了
生产环境直接阻塞整个应用是危险的,可以设logpoint,插入console.log语句,例:'req', req.url。在console看。
5 部署
部署到生产环境上,需要一些工具保证进程稳定运行(tmtools记录进程)
04 延伸话题
WASM未来有发展潜力的模式
NAPI用更底层的代码与nodejs交互