node.js开发实战
<p>1. 什么是RPC调用(远程过程调用)remote procedure call</p><p><img src="https://img2018.cnblogs.com/blog/1075409/201912/1075409-20191202231323133-1830169081.png"></p>
<p>半双工和全双工通信(实现难度和成本) </p>
<p>二进制协议</p>
<p>. 更小的数据包体积</p>
<p>. 更快的编解码速率</p>
<p>2. Buffer 编解码二进制数据包 (node 的二进制Buffer模块)</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">#buffer创建
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 具体用法参见文档</span>
1<span style="color: rgba(0, 0, 0, 1)">. Buffer.from()
</span>2<span style="color: rgba(0, 0, 0, 1)">. Buffer.alloc()
</span><span style="color: rgba(0, 0, 255, 1)">var</span> buffer = Buffer.from('guiqing'); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> <Buffer 67 75 69 71 69 6e 67></span>
<span style="color: rgba(0, 0, 255, 1)">var</span> buffer = Buffer.from('股'); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"><Buffer e8 82 a1></span>
对于默认的utf-<span style="color: rgba(0, 0, 0, 1)">8编码;英文占用一个字节,中文占用三个字节,为16进制
#buffer的写入
buffer.writeInt8
buffer.writeInt16BE
buffer.writeInt16LE
为啥writeInt8没有大小端,是因为一个字节为8位,刚好不需要两位,没有顺序之分<br>原生动态将多个string转为二进制的话,可能还需要获取写入的string对应的字节长度,以便管理下一次写入的offset;<br>可以通过Buffer.byteLength()来获取</span></pre>
</div>
<p>(Protocol Buffers)用来编码二进制数据</p>
<p> protocol-buffers(npm包,用于方便实现编码二进制数据)</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> obj =<span style="color: rgba(0, 0, 0, 1)"> {
a: </span>1<span style="color: rgba(0, 0, 0, 1)">
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> buffer =<span style="color: rgba(0, 0, 0, 1)"> Buffer.from(JSON.stringify(obj))
console.log(buffer.toString())// 可以将json数据直接这样转为二进制数据</span></pre>
</div>
<p>3. net 搭建多路复用的RPC通道</p>
<p><img src="https://img2018.cnblogs.com/blog/1075409/201912/1075409-20191203001800960-610076211.png"></p>
<p> 对应的https://github.com/geektime-geekbang/geek-nodejs/tree/master/chapter2/rpc</p>
<p> 4. HTTP 服务性能测试</p>
<p>压力测试工具(ab、webbench)</p>
<p>通常用ab (https://www.jianshu.com/p/43d04d8baaf7)</p>
<p>找到性能瓶颈</p>
<p>. top (cpu、内存)</p>
<p>. iostat (硬盘)</p>
<p>5. Node.js性能分析工具</p>
<p>1⃣️ 自带的 profile 启动命令的时候带上--prof (eg. node --prof app.js)</p>
<p>这时会生成一个*.log 文件</p>
<p>可以通过命令: node --prof-process *.log > profile.txt (生成文件, 然后主要看这里,看主要的耗时)</p>
<p><img src="https://img2018.cnblogs.com/blog/1075409/201912/1075409-20191203005218953-1274638529.png"></p>
<p> 2⃣️ Chrome devtool (eg. node --inspect-brk app.js)</p>
<p>chrome://inspect 进入</p>
<p><img src="https://img2018.cnblogs.com/blog/1075409/201912/1075409-20191203005649664-1601277151.png"></p>
<p>3⃣️ Clinic.js </p>
<p>4⃣️ 内存分析,可以点击Memory</p>
<p><img src="https://img2018.cnblogs.com/blog/1075409/201912/1075409-20191203195459214-1761825050.png"></p>
<p> </p>
<p> 这个就是你所占有的内存总量</p>
<p>6. 石头剪刀布游戏</p>
<p>1⃣️ process.argv</p>
<p><img src="https://img2018.cnblogs.com/i-beta/1075409/202002/1075409-20200201151747893-1600124441.png"></p>
<p> </p>
<p> </p>
<p> 可以获取到用户输入的指令参数</p>
<p>2⃣️ module.exports 和 exports的区别</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">#lib.js
exports.a </span>= 'hello world'<span style="color: rgba(0, 0, 0, 1)">;
module.exports </span>= <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (){
console.log(</span>'exports被重新赋值了,上面定义的属性获取不到'<span style="color: rgba(0, 0, 0, 1)">)
}
setTimeout(</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(){
console.log(exports); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> {a: 'hello world'}</span>
}, 2000<span style="color: rgba(0, 0, 0, 1)">)
#index.js
const lib </span>= require('./lib.js'); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> lib 是引用类型</span>
console.log(lib); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"></span>
<span style="color: rgba(0, 0, 0, 1)">
lib.b </span>= '我修改了对象'</pre>
</div>
<p>3⃣️ process.stdin</p>
<p><img src="https://img2018.cnblogs.com/i-beta/1075409/202002/1075409-20200201162210831-961833115.png"></p>
<p> 7. callback 为啥采用error-first 模式</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* try catch只能抓到一个调用堆栈内,即一个事件循环里的错误
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> try {</span>
interview(<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (err, res) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (err) {
console.log(</span>'cry'<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
}
console.log(</span>'smile'<span style="color: rgba(0, 0, 0, 1)">)
})
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> } catch (e) {</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)"> console.log('cry')</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)"> }</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> interview(callback) {
setTimeout(() </span>=><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (Math.random() > 0.2<span style="color: rgba(0, 0, 0, 1)">) {
callback(</span><span style="color: rgba(0, 0, 255, 1)">null</span>, 'success'<span style="color: rgba(0, 0, 0, 1)">)
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> throw new Error('fail');</span>
callback(<span style="color: rgba(0, 0, 255, 1)">new</span> Error('fail'<span style="color: rgba(0, 0, 0, 1)">))
}
}, </span>500<span style="color: rgba(0, 0, 0, 1)">)
}</span></pre>
</div>
<p> 8. promise 的状态是和最后一个then或者catch相关,或者是then中的其他promise状态相关</p>
<p><img src="https://img2018.cnblogs.com/i-beta/1075409/202002/1075409-20200202184939283-635530340.png"></p>
<p> </p>
<p> </p>
<p> 9. koa的优势</p>
<p>1⃣️. 不绑定中间间,更简洁</p>
<p>2⃣️. 使用async/await实现中间件,有暂停的能力(await next());在异步的情况下也符合洋葱模型</p>
<p>10. 使用es6模版和vm作为渲染引擎</p>
<div class="cnblogs_code">
<pre>// template.js<br>const fs = require('fs'<span style="color: rgba(0, 0, 0, 1)">);
const vm </span>= require('vm'<span style="color: rgba(0, 0, 0, 1)">);
const templateCache </span>=<span style="color: rgba(0, 0, 0, 1)"> {};
const templateContext </span>=<span style="color: rgba(0, 0, 0, 1)"> vm.createContext({
include: </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (name, data) {
const template </span>= templateCache ||<span style="color: rgba(0, 0, 0, 1)"> createTemplate(name)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> template(data);
}
});
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> createTemplate(templatePath) {
templateCache </span>=<span style="color: rgba(0, 0, 0, 1)"> vm.runInContext(
`(</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (data) {
</span><span style="color: rgba(0, 0, 255, 1)">with</span><span style="color: rgba(0, 0, 0, 1)"> (data) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> \`${fs.readFileSync(templatePath, 'utf-8'<span style="color: rgba(0, 0, 0, 1)">)}\`
}
})`,
templateContext
);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> templateCache
}
module.exports </span>= createTemplate<br><br>// 使用 index.js</pre>
<p>const template = require('./template');</p>
<p>const detailTemplate = template(__dirname + '/template/index.html');</p>
<p>app.use(async (ctx) => {</p>
<p> ctx.status = 200;</p>
<p><em id="__mceDel"> ctx.body = detailTemplate(result);<br>})</em></p>
</div>
<p>渲染引擎模版要提供</p>
<p>1⃣️ include 子模版</p>
<p>2⃣️ 具备防止xss攻击,helper函数</p>
<p>11. graphQL: Facebook开发的实现API服务的库</p>
<p>比Restful的优势在于能够让前端有“自定义查询”数据的能力</p>
<p>koa-graphql(npm包)</p>
<p>12. 前后端同构</p>
<p>场景:服务端渲染,同时前端可以进行无刷新排序和分类等操作</p>
<p>难点:由于我们使用redux或者vuex; 所以数据方面比较难同构, react 可以用 next.js 进行服务端渲染</p>
<p>axios支持运行在浏览器和node.js</p>
<p> 13. 子进程(child_process)和 工作线程(worker_threads)和集群(cluster)</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)"># child_process.fork() 方法是 child_process.spawn(), 能和父进程进行通信
# index.js
const cp </span>= require('child_process'<span style="color: rgba(0, 0, 0, 1)">);
const child_process_demo </span>= cp.fork(__dirname + '/child.js'<span style="color: rgba(0, 0, 0, 1)">);
child_process_demo.send(</span>'hello'<span style="color: rgba(0, 0, 0, 1)">);
#child.js
process.on(</span>'messaage', <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(str) {
console.log(str);
process.send(</span>'world'); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> process是全局变量, 且为当前子进程全局变量,所以只会接收到child_process_demo的消息</span>
})</pre>
</div>
<div class="cnblogs_code">
<pre>const cluster = require('cluster'<span style="color: rgba(0, 0, 0, 1)">);
const os </span>= require('os'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (cluster.isMaster) {
</span><span style="color: rgba(0, 0, 255, 1)">for</span>(let i = 0; i < os.cpus().length / 2; i++<span style="color: rgba(0, 0, 0, 1)">) {
cluster.fork();
};
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
require(</span>'./app.js'<span style="color: rgba(0, 0, 0, 1)">);
};
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">子进程启动的时候也会执行这个文件,并且isMaster是false</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)"> cluster 启动多个子进程,但是能监听同个端口是进行了处理的。</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)"> 处理成类似server.listen({fd: 7});这里不太清楚没细究</span></pre>
</div>
<p>14. 反向代理和缓存服务 (nginx)</p>
<p><img src="https://img2018.cnblogs.com/i-beta/1075409/202002/1075409-20200205171907836-1588689391.png"></p>
<p> </p>
<p> 15. serverless (渐进式)</p>
<p> 云函数(自行百度理解)</p>
<div class="cnblogs_code">
<pre>const fs = require('fs'<span style="color: rgba(0, 0, 0, 1)">);
const mkdirp </span>= require('mkdirp'<span style="color: rgba(0, 0, 0, 1)">);
const webpack </span>= require('webpack'<span style="color: rgba(0, 0, 0, 1)">);
const mfs </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> (require('memory-fs'<span style="color: rgba(0, 0, 0, 1)">));
module.exports </span>= <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (
businessName,
dataJSPath,
templatePath
) {
mkdirp.sync(__dirname </span>+ '/../business/' +<span style="color: rgba(0, 0, 0, 1)"> businessName);
fs
.createReadStream(templatePath)
.pipe(fs.createWriteStream(__dirname </span>+ '/../business/' + businessName + '/template.tpl'<span style="color: rgba(0, 0, 0, 1)">));
const compileTask </span>=<span style="color: rgba(0, 0, 0, 1)"> webpack({
mode: </span>'development'<span style="color: rgba(0, 0, 0, 1)">,
devtool: </span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
target: </span>'node'<span style="color: rgba(0, 0, 0, 1)">,
entry: dataJSPath,
module: {
rules: [
{ test: </span>/.proto$/, use: 'text-loader'<span style="color: rgba(0, 0, 0, 1)"> }
]
},
output: {
path: </span>"/whatever"<span style="color: rgba(0, 0, 0, 1)">,
filename: </span>"data.js"<span style="color: rgba(0, 0, 0, 1)">
}
});
compileTask.outputFileSystem </span>= mfs; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 这里可以借鉴,将webpack打包出来的文件先存在内存</span>
<span style="color: rgba(0, 0, 0, 1)">
compileTask.run(</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(err) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (err) { <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> }
const content </span>= mfs.readFileSync('/whatever/data.js'<span style="color: rgba(0, 0, 0, 1)">)
fs.writeFileSync(__dirname </span>+ '/../business/' + businessName + '/data.js'<span style="color: rgba(0, 0, 0, 1)">, content);
})
}</span></pre>
</div>
<p> </p>
<div id="gtx-trans" style="position: absolute; left: 263px; top: 6908px"> </div><br><br>
来源:https://www.cnblogs.com/luguiqing/p/11974334.html
頁:
[1]