callback
Node.js 使用回调
var http = require('http');
http.get({host: 'shapeshed.com'}, function(res) {
// 这个回调时发生在远程服务器发回响应之后发生的
console.log('Got response: '+res.statusCode);
}).on('error', function(e) {
console.log('Got error: '+e.message);
});
同步和异步
同步和阻塞时可以互用的两个概念,指的是代码(脚本)的执行会在函数返回之前停止,如下面的代码,在 fetchPage()
运行时,它阻塞了整个脚本的运行。其他接下来的操作必须等待。
// blocking code
function sleep(milliseconds) {
var start = new Date().getTime();
while((new Date().getTime() - start) < milliseconds) {
// 超过给定时间才从该循环跳出,模拟了 setTimeout
}
}
function fetchPage() {
console.log('fetching page');
sleep(2000);
console.log('page fetched');
}
function fetchApi() {
console.log('fetching api');
sleep(2000);
console.log('api fetched');
}
fetchPage();
fetchApi();
异步和非阻塞是可以互用的概念,指的是基于回调的、允许脚本并行(并发)执行操作的方法。脚本无需等待某个操作的结果,因为操作结果会在事件发生时由回调函数来处理。
// non-blocking code
var http = require('http');
function fetchPage() {
console.log('fetching page');
http.get({host: 'baidu.com', path: '/?delay=2000'}, function(res) {
console.log('page fetched');
}).on('error', function(e) {
console.log('error occured'+e);
});
}
function fetchApi() {
console.log('fetching api');
http.get({hots: 'baidu.com', path: '/?delay=2000'}, function(res) {
console.log('api fetched');
}).on('error', function(e) {
console.log('error occured'+e);
});
}
fetchPage();
fetchApi();
事件循环
该机制是确保 Node.js 可以使用回调进行工作的基石。事件循环使得系统可以将回调函数先保存起来,而后当事件发生时再运行。而事件可以是数据库返回数据,也可以是http请求返回数据等。控制流在事件发生后需要执行回调时会回到需要的位置上。
使用基于事件循环进行编程,实际上关键思想是,将代码围绕着事件来构架而不是按照期待中的输入顺序来构架。
由于Js中的事件循环以单一进程为基础,所以为了确保高性能,需要遵循以下规则:
- 函数必须快速返回
- 函数不得阻塞
- 长时间运行的操作必须移到另一个进程中
由于以上的第三点,如果程序或函数需要长时间运行才能完成处理,那么事件循环就不是个好选择。Node.js 所不适合的地方包括处理大量数据或者长时间运行计算等。Node.js 旨在在网络中推送数据并瞬间完成。