回调和异步调用的关系

首先明确一点,回调并非是异步调用,回调是一种解决异步函数执行结果的处理方法。在异步调用,如果我们希望将执行的结果返回并且处理时,可以通过回调的方法解决。为了能够更好的区分回调和异步回调的区别,我们来看一个简单的例子,代码如下:

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基于事件驱动的回调的更多相关文章

  1. 从医生看病和快餐店点餐理解Node.js的事件驱动

    第一个例子是关于医生看病. 在美国去看医生,需要填写大量表格,比如保险.个人信息之类,传统的基于线程的系统(thread-based system),接待员叫到你,你需要在前台填写完成这些表格,你站着 ...

  2. 创业笔记-Node.js入门之基于事件驱动的回调

    基于事件驱动的回调 这个问题可不好回答(至少对我来说),不过这是Node.js原生的工作方式.它是事件驱动的,这也是它为什么这么快的原因. 你也许会想花点时间读一下Felix Geisendörfer ...

  3. 理解Node.js事件驱动编程

    Node.js现在非常活跃,相关生态社区已经超过Lua(基本上比较知名的功能都有nodejs模块实现). 但是我们为何要使用Node.Js?相比传统的webserver服务模式,nodejs有什么优点 ...

  4. 理解Node.js的事件轮询

    前言 总括 : 原文地址:理解Node.js的事件轮询 Node小应用:Node-sample 智者阅读群书,亦阅历人生 正文 Node.js的两个基本概念 Node.js的第一个基本概念就是I/O操 ...

  5. 深度理解Node.js单线程模型

    Node.js采用 事件驱动 和 异步I/O 的方式,实现了一个单线程.高并发的运行时环境,而单线程就意味着同一时间只能做一件事,那么Node.js如何利用单线程来实现高并发和异步I/O?本文将围绕这 ...

  6. Node.js:创建应用+回调函数(阻塞/非阻塞)+事件循环

    一.创建应用 如果我们使用PHP来编写后端的代码时,需要Apache 或者 Nginx 的HTTP 服务器,并配上 mod_php5 模块和php-cgi.从这个角度看,整个"接收 HTTP ...

  7. 方便大家学习的Node.js教程(一):理解Node.js

    理解Node.js 为了理解Node.js是如何工作的,首先你需要理解一些使得Javascript适用于服务器端开发的关键特性.Javascript是一门简单而又灵活的语言,这种灵活性让它能够经受住时 ...

  8. 什么是node.js的事件驱动编程

    Node.js现在非常活跃,相关生态社区已经超过Lua(基本上比较知名的功能都有nodejs模块实现).但是我们为何要使用Node.Js?相比传统的webserver服务模式,nodejs有什么优点优 ...

  9. Node.js自学笔记之回调函数

    写在前面:如果你是一个前端程序员,你不懂得像PHP.Python或Ruby等动态编程语言,然后你想创建自己的服务,那么Node.js是一个非常好的选择.这段时间对node.js进行了简单的学习,在这里 ...

随机推荐

  1. 爬虫请求库——requests

    请求库,即可以模仿浏览器对网站发起请求的模块(库). requests模块 使用requests可以模拟浏览器的请求,requests模块的本质是封装了urllib3模块的功能,比起之前用到的urll ...

  2. AlertWindowManager 弹出提示窗口使用帮助(下)

    //显示消息提示框 //function TdxAlertWindowManager.Show(const ACaption, AText: string; AImageIndex: TcxImage ...

  3. Dockerfile语法解析

    Dockfile介绍 从上到下依次执行 每次执行一条指令就创建一个镜像层 第一条指令必须是FROM    表示需要构建的镜像是由哪个镜像为基础镜像   后续的指令运行于此基准镜像所提供的运行环境 可以 ...

  4. 【UML】-NO.42.EBook.5.UML.1.002-【UML 大战需求分析】- 活动图 (Activity Diagram)

    1.0.0 Summary Tittle:[UML]-NO.42.EBook.1.UML.1.002-[UML 大战需求分析]- 活动图 Style:DesignPattern Series:Desi ...

  5. 背景图宽高100%无法无法显示的问题【body设置relative,当前元素absolute】

    以下1,2两个关键元素 body{   width:100%;   height:100%;   position:relative; //1 } .login-form { width: 100%; ...

  6. componentsSeparatedByString 的注意事项

    componentsSeparatedByString 两种情景 1. 没有分割符也生成一个数组,元素就是整个字符串本身,那你就需要判断“”这种字符串. 2. 分割的元素如果是相同的字符串,指向的是同 ...

  7. 解决PuTTY中文乱码

    转载:http://lhdeyx.blog.163.com/blog/static/3181969720091115113716947/ 打开putty,选择 Category中的Windows--- ...

  8. Centos6.5建立本地YUM源

    很多情况下公司的服务器是不允许连外网的,那么安装软件的时候就很不方便了,这里就需要建立一个本地YUM源了. 文件位置:/etc/yum.repos.d/    后缀一定是.repo结束. 下面我们搭建 ...

  9. LR、Poly2、FM、FFM

    1. LR LR的linear Margin: 假设特征之间是相互独立的,忽略了feature pair等高阶信息:在LR中,特征组合等高阶信息是通过特征工程在特征侧引入的,那么有哪些模型不需要通过特 ...

  10. plt.contour 与 plt.contourf

    contour:轮廓,等高线 1.为等高线上注明等高线的含义: cs = plt.contour(x, y, z) plt.clabel(cs, inline=True, fontsize=10)#i ...