深入理解Node.js基于事件驱动的回调
回调和异步调用的关系
首先明确一点,回调并非是异步调用,回调是一种解决异步函数执行结果的处理方法。在异步调用,如果我们希望将执行的结果返回并且处理时,可以通过回调的方法解决。为了能够更好的区分回调和异步回调的区别,我们来看一个简单的例子,代码如下:
function waitFive(name, function_name){
var pus = 0;
var currentDate = new Date();
while(pus < 5000){
var now = new Date();
pus = now - currentDate;
}
function_name(name);
}
function echo(name){
console.log(name);
}
waitFive("bob", echo);
console.log('its over');
以上代码是一个回调逻辑,但不是一个异步代码逻辑,因为其中并没有涉及 Node.js 的异步调用接口。waitFive()函数执行时,整个代码执行过程都会等待 waitFive() 函数的执行,而并非如异步调用那样waitFive未结束,还会继续执行console.log(‘its over’);
因此,回调还是一种阻塞式调用。
异步函数往往不是直接返回执行结果,而是通过事件驱动方式,将执行结果返回到回调函数中,之后在回调函数中处理相应的逻辑代码。
Node.js中很多API的调用模式是异步调用的,因此在学习Node.js过程中理解异步调用、同步调用和回调是非常重要的。
为什么异步函数需要回调函数?
先看这样一个例子:
var dns = require('dns'); // require dns 模块
var address = dns.resolved4('www.baidu.com', function(address){});//dns 同步解析
console.log(address);
当我们获取address值时,会出现异常,提示address没有定义undefined。打印出address,可以看到第二个例子结果为null,原因很简单,异步函数dns.resolve4()还未执行结束时,就已经执行到 console.log(address),因此最终 address 为 null。既然异步函数出现这个问题,我们就可以使用回调去获取函数。如下代码,通过回调函数获取执行的结果 address 值:
var dns = require('dns');
dns.resolve4('www.baidu.com', function(address){
console.log(address);
})
Node.js —— 基于事件驱动的回调
为什么它对我们用 Node.js 写网络应用是具有意义的?
当我们使用 http.createServer 方法的时候,我们当然不只是想要一个侦听某个端口的服务器,我们还想要它在服务器收到一个HTTP请求的时候做点什么。问题是,这是异步的:请求任何时候都可能到达,但是我们的服务器却跑在一个单进程中。
写PHP应用的时候,我们一点也不为此担心:任何时候当有请求进入的时候,网页服务器(通常是Apache)就为这一请求新建一个进程,并且开始从头到尾执行相应的PHP脚本。
我们先来看一个基于Node.js简约而不简单的HTTP服务器:
var http = require("http");
http.createServer(function(request, response){
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}).listen(8888);
那么在我们的Node.js程序中,当一个新的请求到达8888端口的时候,我们怎么控制流程呢?
嗯,这就是Node.js/JavaScript的事件驱动设计能够真正帮上忙的地方了 —— 虽然我们还得学一些新概念才能掌握它。让我们来看看这些概念是怎么应用在我们的服务器代码里的。
我们创建了服务器,并且向创建它的方法传递了一个函数。无论何时我们的服务器收到一个请求,这个函数就会被调用。我们不知道这件事情什么时候会发生,但是我们现在有了一个处理请求的地方:它就是我们传递过去的那个函数。至于它是被预先定义的函数还是匿名函数,都无关紧要了。这个就是传说中的 回调(Node.js中的异步回调)。
让我们再来琢磨琢磨 [ Node.js中的异步回调 ] 这个概念。
我们怎么证明在创建完服务器之后,即时没有HTTP请求进来,我们的回调函数也没有被调用的情况下,我们的代码还继续有效呢?试试这个:
var http = require("http");
http.createServer(function(request, response){
console.log("Request received.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}).listen(8888);
console.log("Server has started.");
注意:在匿名回调函数触发的地方,我们用 console.log 输出了一段文本;在HTTP服务器开始工作之后,也输出一段文本。
当我们与往常一样,运行 node server.js 时,它会马上在命令行上输出 “Server has started.”。当我们向服务器发出请求(在浏览器访问http://localhost:8888),“Request received.”这条消息就会在命令行中出现。(请注意,当我们在服务器访问网页时,我们的服务器可能会输出两次“Request received.”。那是因为大部分浏览器都会在你访问 http://localhost:8888 时尝试读取 http://localhost:8888/favicon.ico) —— 这就是事件驱动的异步服务器端 JavaScript 和它的回调啦!
深入理解Node.js基于事件驱动的回调的更多相关文章
- 从医生看病和快餐店点餐理解Node.js的事件驱动
第一个例子是关于医生看病. 在美国去看医生,需要填写大量表格,比如保险.个人信息之类,传统的基于线程的系统(thread-based system),接待员叫到你,你需要在前台填写完成这些表格,你站着 ...
- 创业笔记-Node.js入门之基于事件驱动的回调
基于事件驱动的回调 这个问题可不好回答(至少对我来说),不过这是Node.js原生的工作方式.它是事件驱动的,这也是它为什么这么快的原因. 你也许会想花点时间读一下Felix Geisendörfer ...
- 理解Node.js事件驱动编程
Node.js现在非常活跃,相关生态社区已经超过Lua(基本上比较知名的功能都有nodejs模块实现). 但是我们为何要使用Node.Js?相比传统的webserver服务模式,nodejs有什么优点 ...
- 理解Node.js的事件轮询
前言 总括 : 原文地址:理解Node.js的事件轮询 Node小应用:Node-sample 智者阅读群书,亦阅历人生 正文 Node.js的两个基本概念 Node.js的第一个基本概念就是I/O操 ...
- 深度理解Node.js单线程模型
Node.js采用 事件驱动 和 异步I/O 的方式,实现了一个单线程.高并发的运行时环境,而单线程就意味着同一时间只能做一件事,那么Node.js如何利用单线程来实现高并发和异步I/O?本文将围绕这 ...
- Node.js:创建应用+回调函数(阻塞/非阻塞)+事件循环
一.创建应用 如果我们使用PHP来编写后端的代码时,需要Apache 或者 Nginx 的HTTP 服务器,并配上 mod_php5 模块和php-cgi.从这个角度看,整个"接收 HTTP ...
- 方便大家学习的Node.js教程(一):理解Node.js
理解Node.js 为了理解Node.js是如何工作的,首先你需要理解一些使得Javascript适用于服务器端开发的关键特性.Javascript是一门简单而又灵活的语言,这种灵活性让它能够经受住时 ...
- 什么是node.js的事件驱动编程
Node.js现在非常活跃,相关生态社区已经超过Lua(基本上比较知名的功能都有nodejs模块实现).但是我们为何要使用Node.Js?相比传统的webserver服务模式,nodejs有什么优点优 ...
- Node.js自学笔记之回调函数
写在前面:如果你是一个前端程序员,你不懂得像PHP.Python或Ruby等动态编程语言,然后你想创建自己的服务,那么Node.js是一个非常好的选择.这段时间对node.js进行了简单的学习,在这里 ...
随机推荐
- JDK源代码学习系列04----ArrayList
JDK源代码学习系列04----ArrayList 1 ...
- mysql 5.7.12 新增 X plugin x 协议 详解
mysql 5.7.12 新增 X plugin x 协议 详解http://xiaozhong991.blog.51cto.com/2354914/1763792 x 协议 操作nosql数据库 ...
- 简单好用的计算器:bc
1.简单好用的计算器:bc (1)参数: (2)实例: 执行浮点运算和一些高级函数 设定小数精度(数值范围) 进制转换 执行结果为:11000000,这是用bc将十进制转换成二进制 计算平方和平方根:
- Elemet-技巧
<el-table-column prop="> </el-table-column> 效果: append-to-body 解决el-dialog 弹窗遮罩为题 & ...
- 八种排序算法--java实现(转)
(转:http://blog.csdn.net/without0815/article/details/7697916) 8种排序之间的关系: 1, 直接插入排序 (1)基本思想:在要排序的一组数中, ...
- 十步完全理解SQL(转载)
1. SQL 是一种声明式语言 首先要把这个概念记在脑中:“声明”. SQL 语言是为计算机声明了一个你想从原始数据中获得什么样的结果的一个范例,而不是告诉计算机如何能够得到结果.这是不是很棒? (译 ...
- Spark创建空的DataFrame
前言 本文主要给出Spark创建空的DataFrame的代码示例,这里讲的空的DataFrame主要指有列名(可以自己随意指定),但是没有行的DataFrame,因为自己在开发过程中有这个需求,之前并 ...
- jode反编译软件
1.下载 http://jode.sourceforge.net/(官网) https://sourceforge.net/projects/jode/files/(下载地址) 2.使用 下载的jod ...
- 阿里云香港主机自动换IP
为什么要写这个脚本原因你懂的,现在都是直接封IP pip3 install aliyun-python-sdk-alidns aliyun-python-sdk-domain aliyun-pytho ...
- shell 脚本中如何添加多行注释
shell中有时会用到多行注释,一种时vim的快捷方式,我不太熟悉,一种是如下 :<<! ......! 使用: :<< !.......! 比如: :<< ! ...