回调和异步调用的关系

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

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. Python3学习之路~8.2 socket简单实例 实现ssh 发送大量数据

    实例1: 利用socket模拟客户端和服务器端各自收发一次数据: #Author:Zheng Na # 客户端 import socket # 声明socket类型,同时生成socket连接对象 cl ...

  2. Building an (awesome) API with NancyFX 2.0 + Dapper

    http://blog.nandotech.com/post/2016-10-25-nancyfx-webapi-dapper/?utm_source=tuicool&utm_medium=r ...

  3. 【剑指offer】二叉搜索树与双向链表

    一.题目: 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向. 二.思路: 对于一棵搜索二叉树来说,中序遍历得到的即是有序的结果,所以整 ...

  4. caffe SSD目标检测lmdb数据格式制作

    一.任务 现在用caffe做目标检测一般需要lmdb格式的数据,而目标检测的数据和目标分类的lmdb格式的制作难度不同.就目标检测来说,例如准备SSD需要的数据,一般需要以下几步: 1.准备图片并标注 ...

  5. mysql的查询

    1.单表查询 单表查询的语法 SELECT 字段1,字段2... FROM 表名 WHERE 条件 GROUP BY field HAVING 筛选 ORDER BY field LIMIT 限制条数 ...

  6. ssm框架整合

    1.1 整合的思路 1.1.1 Dao层 使用mybatis框架.创建SqlMapConfig.xml.(可以是任意名字) 创建一个applicationContext-dao.xml   (通过sp ...

  7. SOA架构大概思路

    1.创建父工程(pom)管理jar包版本 2.创建子工程common工程(jar)管理通用工具类.通用pojo 3.创建服务层工程(聚合工程(pom)) 3.1.创建模块(dao.pojo.inter ...

  8. 【LeetCode每天一题】Add Two Numbers(两链表相加)

    You are given two non-empty linked lists representing two non-negative integers. The digits are stor ...

  9. [LeetCode] 613. Shortest Distance in a Line_Easy tag: SQL

    Table point holds the x coordinate of some points on x-axis in a plane, which are all integers. Writ ...

  10. iOS 崩溃分析

    崩溃统计分析,在APP中是非常常见一种优化APP,发现APP的BUG的方式. 1.异常处理 可通过try catch 方式处理,如果发生异常,会走catch ,最终走fianlly.对一些我们不想他崩 ...