阻塞和非阻塞IO
- node引入了一个复杂的概念,共享状态的并发
- 得对回调函数如何修改当前内存中得变量(状态)特别小心
- 特别注意对错误的处理是否会潜在的在修改这些状态,从而导致整个进程不可用
- 时刻避免运行时错误的出现
阻塞
- node里面有事件轮询,意味本质上来说,node会先注册时间,随后不断地询问内核这些时间是否已经分发,当时间分发时,对应的毁掉函数就会被触发,然后继续执行下去,如果没有事件触发,则继续执行其他代码,知道有新事件时,再去执行对应的回调函数
//事件轮询
console.log("hello");
setTimeout(() => {
console.log('world');
}, 4000);
console.log('bye');
单线程的世界
- node 是单线程的,在没有第三方模块的版主下是无法改变这一事实的
let start = Date.now();
setTimeout(function () {
console.log(Date.now() -start);
for (let i = 0 ; i<100000000;i++){
}
},1000);
setTimeout(function () {
console.log(Date.now() - start);
}, 2000);
1001
2000当第一个时间分发下去的时候,会执行js毁掉函数,由于回调函数需要执行很长一段时间
所以下一个事件轮询的时间就不一定是2秒
node的众多模块都是非阻塞的,执行任务也变成了异步
错误处理
- node应用依托扎起一个拥有大量共享状态的大进程中
- 例子
let http = require('http');
http.creatServer(function(){
thow new Error("错误不会被捕捉")
}).listen(3000)
- 这个代码是跑不动的 因为报错没有被捕获 进程会崩溃
- 避免上面的问题
- 我们需要添加一个
uncatchException
处理器,这个时候进程不会退出,并且之后的事情都是可空的 - 例子
let http = require('http');
process.on('uncaughtException', function (err) {
console.log(err);
process.exit(1);
});
http.createServer(function () {
throw new Error("错误跳出来了");
}).listen(8080);
- 除了uncaughtException 和error时间外,绝大部分node异步api接受的回调函数,第一个就是错误对象或者是null
let fs = require('fs');
fs.readFile('', function (err, data) {
if (err) return console.error(err);
console.log(data);
});
- 错误的处理每一步都很重要,它能让你更加安全
堆栈追踪
- 在js中,当错误发生的时候,在错误信息中可以看到一系列的函数调用,这称为堆栈追踪
- 例子
function c() {
b();
}
function b (){
a();
}
function a() {
throw new Error("错误出来额")
}
c();
/*
* E:\TheGreatNodeJs\day01\12.堆栈追踪.js:11
throw new Error("错误出来额")
^
Error: 错误出来额
at a (E:\TheGreatNodeJs\day01\12.堆栈追踪.js:11:11)
at b (E:\TheGreatNodeJs\day01\12.堆栈追踪.js:7:5)
at c (E:\TheGreatNodeJs\day01\12.堆栈追踪.js:2:5)
at Object.<anonymous> (E:\TheGreatNodeJs\day01\12.堆栈追踪.js:14:1)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
at Function.Module.runMain (module.js:693:10)
*/
- 从上可以看到导致错误发生的函数调用路径,下面我们来引入事件轮询查看一下
function c() {
b();
}
function b (){
a();
}
function a() {
setTimeout(function () {
throw new Error("错误出来额")
},10)
}
c();
/*
* E:\TheGreatNodeJs\day01\13.堆栈追踪(事件轮询.js:13
throw new Error("错误出来额")
^
Error: 错误出来额
at Timeout._onTimeout (E:\TheGreatNodeJs\day01\13.堆栈追踪(事件轮询.js:13:15)
at ontimeout (timers.js:498:11)
at tryOnTimeout (timers.js:323:5)
at Timer.listOnTimeout (timers.js:290:5)
* */
- 这里面try catch是不可行的,这会直接抛出未捕获异常,并且catch永远都不会执行