node.js之回调函数
发现可以全文修改。那我就趁这几天不忙,,把nodejs的笔记全部整理一下吧。。先立个flag在这里,虽然没人看,但是也是学习的动力。。。
1.1.1 异步操作
- 首先先了解什么是异步。说道异步,就会联系出来的他 的孪生兄弟——同步(synchronous),“同步模式”就是上一段的模式,后一个人物等待前一个人物结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的,同步的。
- 而异步模式则完全不同,每一个任务有一个或多个回调函数,(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的,是异步的。异步模式非常重要。在浏览器端,好事很长的操作都应该异步执行。避免浏览器失去响应,最好的例子回事ajax操作。
- 举一个大家都熟悉的例子:
<body>
<button id="Button">展示异步操作</button>
<script>
var Button=document.getElementById('Button');
Button.function(){
alert('展示异步操作--a');
}
alert('展示异步操作--b');
</script>
</body>
- 但是我一直有疑惑在于,JavaScript不是单线程语言吗?那他是如何做到异步操作的?所以——但凡“ 即是单线程又是异步 ”的语言都有一个共同的特点:它们是 event-driven 的,所以 Javascript 异步的实现也与其事件机制关系密切。
- 在浏览器端的JavaScript实现了两个很重要的api,他们分别是定时器和AJAX请求。
定时器:
我。。。哦对啊,当你用定时器的时候,总会出现异步的情况啊
所以说,定时器如setTimeout被执行时,由浏览器的定时器线程执行的定时级数,而并不是JavaScript执行线程赋值计数。定时器线程在定时时间触发延时事件并将延时事件推入JavaScript事件队列。当JavaScript主线程同步diamante执行完毕时,会去轮询该事件对垒,取出最开始事件的处理函数推入主线程中被执行
AJAX
AJAX请求和定时器类似,同样是委托浏览器线程代为执行好事任务,这里是皆有浏览器的HTTP请求线程发起对服务器的请求,在请求得到响应后出发请求完成事件,将回调函数推入事件按队列等待执行
当然,上面只是浏览器端,在NodeJs的异步实现和浏览器端有所不同,
在NodeJs中Libuv为Nodejs提供了跨平台,线程池,事件池,异步I/O等能力,是Nodejs如此强大的关键。Libuv为上层的Nodejs提供了统一的API调用,使其不考虑平台差距,隐藏了底层实现。
我。。。实在是不好理解了,复制粘贴算了
发起 I/O 调用
1 用户通过 Javascript 代码调用 NodeJS 核心模块,将参数和回调传入核心模块
2 NodeJS 核心模块将传入参数和回调封装为一个请求对象
3 将这个请求对象推入到I/O线程池中等待执行
4 Javascript 发起的异步调用结束,Javascript 线程继续执行后续操作
执行回调
1 异步任务完成之后,会将结果存放在请求对象的 result 属性上,并发出操作完成通知
2 每次事件循环时会检查 I/O 线程池中是否存在已经完成的 I/O 操作,如果有就将请求事件加入到I/O观察者队列当中(事件队列),之后当作事件处理
3 处理I/O观察者事件时,会将之前封装在请求对象中的回调函数取出,并将 result 参数传入执行,以完成 Javascript 回调的目的
我们知道 NodeJS 非常适合开发 IO 密集型应用,但并不适合开发 CPU(计算) 密集型应用。为什么会这样呢?因为 NodeJS 异步的天性,在处理并发 IO 的时候不会阻塞主线程,实际上这种异步是借助于多线程实现的,IO 任务完成之后排队等待主线程执行。因为 NodeJS 主线程执行同步代码的速度非常之快,所以完全可以 hold 得住大规模的并发请求。但这也有存在例外,如果 NodeJS 主线程在执行同步任务的时候遇到一些计算量非常大,或者执行循环太久,等非常耗时的操作的时候,就会导致后续的代码以及事件队列里已完成的 IO 任务迟迟得不到执行,严重拖垮 NodeJS 的性能。
JavaScript是单线程语言,异步函数是由nodejs V8提供的事件完成的。
Node.js使用事件驱动模型,当web server接收到请求,就把它关闭然后进行处理,然后去服务下一个web请求。
当这个请求完成,它被放回处理队列,当到达队列开头,这个结果被返回给用户。
这个模型非常高效可扩展性非常强,因为webserver一直接受请求而不等待任何读写操作。(这也被称之为非阻塞式IO或者事件驱动IO)
在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数。
1.1.2 回调函数(主要内容来源于菜鸟教程)
Node.js异步编程的直接体现就是回调。异步编程依托于回调来实现,但不能说是用了回调后程序就异步化了。
回调函数在完成任务后就会被调用,Node使用了大量的回到函数,Node所有API都支持回调函数。
例如,我们可以一边读取文件,一边执行其他命令,在文件读取完成后,我们将文件内容作为回调函数的参数返回。这样在执行代码时就没有阻塞或等待文件 I/O 操作。这就大大提高了 Node.js 的性能,可以处理大量的并发请求。
回调函数一般作为函数的最后一个参数出现:
function foo1(name, age, callback) { }
function foo2(value, callback1, callback2) { }
举一个应用了回调函数的例子 :
var fs=require("fs");
fs.readFile('input.txt',function(err,data){
if(err) return console.error(err);
});
console.log("程序执行结束!")