注:此文是node.js实战读后的总结。

在平常的脚本语言中都是同步进行的,比如php,服务器处理多个请求的方法就是并行这些脚本。多任务处理,多线程等等。但是这种处理方式也有一个问题:每一个进程或者线程都会耗费大量的系统资源。如果有一种方法可以最大化的利用CPU的计算能力和可用内存以减少资源浪费那就极好了。这样,我们的node.js就应运而生了。

上一个node.js最简单的异步编程案例:

 var fs = require('fs');

 var file;

 fs.open(
'info.txt','r',
function(err,handle){
var buf = new Buffer(100000);
fs.read(
handle,buf,0,100000,null,
function(err,length){
console.log(buf.toString('utf8',0,length));
fs.close(handle,function(){});
}); }
);

从这个例子我们就可以看到在异步函数中使用的最多的回调函数,这些回调函数至少包含一个参数,即最后操作的状态(成功还是失败),一般而言还有第二个参数,即最后操作返回的结果或信息(比如文件句柄,数据库连接,查询到的数据等),一些回调函数可能还包含更多的参数.假设err代表返回的状态参数,则该参数的值一般会有以下几种情况:1.null:表示操作成功,并且会有一个返回值(如果你需要的话).2.一个error对象的实例:通常人们习惯在error对象上添加code字段并且用message字段来保存错误信息(注:这种方式可以让我们写出的非阻塞代码更具可控性)。对上面的代码进行优化加上错误处理:

 var fs = require('fs');

 var file;

 fs.open(
'info.txt','r',
function(err,handle){
//第一种错误处理方式
if(err)
{
console.log("ERROR:"+ err.code + "("+err.message+")");
return;
}
var buf = new Buffer(100000);
fs.read(
handle,buf,0,100000,null,
function(err,length){
//第二种错误处理方式
if(err){
console.log("ERROR:"+err.code+"("+err.message+")");
}else{
console.log(buf.toString('utf8',0,length));
fs.close(handle,function(){});
} }); }
);

但是,在异步处理的过程中得注意this的用法以及函数作用域的变化,看下面的代码:

 var fs = require('fs');

 function FileObject(){
this.filename = ''; this.file_exists = function(callback){
console.log("About to open:"+this.filename);
fs.open(this.filename,'r',function(err,handle){
if(err){
console.log("Can't open:"+ this.filename);
callback(err);
return;
}
fs.close(handle,function(){});
callback(null,true);
});
};
} var fo = new FileObject();
fo.filename = 'info';
fo.file_exists(function(err,results){
if(err){
console.log("ERROR:"+err.code+"("+err.message+")");
return;
}
console.log("file exists!!!");
});

我们原本以为输出的应该是:

About to open:info

Can't open:info

但是实际上确实:

About to open:info

Can't open:undefined

ERROR:ENOENT(ENOENT, open 'G:\nodejs\info')

这是为什么呢?在我们的理解中,大多数情况下,当一个函数嵌套在另一个函数中时,他就会自动继承父函数的作用域,因而就能访问所有的变量了。但是为什么我们嵌套的回调函数却没有出现我们以为的输出呢?

这个问题得归结于this关键字和异步回调函数本身。在我们调用fs.open函数的时候,他会先初始化自己,然后调用底层的操作系统函数(在我们的代码中,就是打开文件),并且把回调函数插入到node.js的事件队列中去,执行完会立即返回给file_exists函数,然后退出。当fs.open完成任务后,node就会调用该回调函数,但此时,该函数已经不再拥有FileObject这个类的继承关系了,所以回调函数会重新赋予新的this指针,在这一过程中我们就丢失了我们的FileObject的this指针,故我们就不能访问我们的file_name。但是在这个过程中,回调函数的作用域还保留着。这里关系到nodejs的事件模式(参考资料:http://nodejs.org/docs/latest/api/events.html),这个也是nodejs的一个重要特性,我们现在不多说。这种错误最常见的解决方法就是把消失的this指针保存在变量中,下面我们来重写

 this.file_exists = function(callback){
//用一个变量来储存this指针
var self = this;
console.log("About to open:"+self.filename);
fs.open(this.filename,'r',function(err,handle){
if(err){
console.log("Can't open:"+ self.filename);
callback(err);
return;
}
fs.close(handle,function(){});
callback(null,true);
});
};

好了,这样我们的输出就和我们想象中的一样了,我们在写代码时一定不要忘了this的变化,不然就可能出现很多bug = = .

好,我们接着说.我们都知道Node运行在单线程中,使用事件轮询来调用外部函数和服务。它将回调函数插入事件队列中来等待响应,并且尽快执行回调函数。好,下面我们来看一个函数,这个函数的功能就是计算两个数组的交叉元素:

 function compute_intersection(arr1,arr2,callback){
var results = [];
for(var i = 0; i<arr1.length; i++)
for(var j = 0; j<arr2.length; j++){
if(arr1[i] == arr2[j]){
results.push(arr1[i]);
bareak;
}
}
callback(null,true);
}

当我数组中的元素特别大时,该函数就会耗费大量的计算时间。我们知道在单线程模式中,node.js在同一时间只能做一件事,所以这耗费的大量时间将会成为一个问题。而比如其他一些计算哈希。摘要(digest)或者其他一下耗费时间的操作就可能导致应用处于假死的状态。所以说node.js并不适合计算服务器,nodejs更适合常见的网络任务,比如那些需要大量I、O或者需要向其他服务请求的任务,如果需要一个大量计算的服务器,第一个解决方法就是把这些操作迁移到其他服务器上去,然后用nodejs远程调用。但如果只是偶尔执行这种任务,那么还有第二种解决方法,那就是利用全局对象process的nextTick方法,该方法的作用就是告诉系统,我不要执行控制权,你在你空闲的时候执行我给你的函数就行了.

好,异步中的一些陷井和基本已经介绍完了,欢迎大家补充。

Node.js 异步模式浅析的更多相关文章

  1. node.js异步编程的几种模式

    Node.js异步编程的几种模式 以读取文件为例: 1.callback function const fs = require('fs'); //callback function fs.readF ...

  2. 深入理解node.js异步编程:基础篇

    ###[本文是基础内容,大神请绕道,才疏学浅,难免纰漏,请各位轻喷] ##1. 概述 目前开源社区最火热的技术当属Node.js莫属了,作为使用Javascript为主要开发语言的服务器端编程技术和平 ...

  3. Node.js异步处理CPU密集型任务

    Node.js异步处理CPU密集型任务 Node.js擅长数据密集型实时(data-intensive real-time)交互的应用场景.然而数据密集型实时应用程序并非仅仅有I/O密集型任务,当碰到 ...

  4. node.js异步编程解决方案之Promise用法

    node.js异步编程解决方案之Promise var dbBase = require('../db/db_base'); var school_info_db = require('../db/s ...

  5. 用简单的 Node.js 后台程序浅析 HTTP 请求与响应

    用简单的 Node.js 后台程序浅析 HTTP 请求与响应 本文写于 2020 年 1 月 18 日 我们来看两种方式发送 HTTP 请求,一种呢,是命令行的 curl 命令:一种呢是直接在浏览器的 ...

  6. node.js 异步式I/O 与事件驱动

    Node.js 最大的特点就是异步式 I/O(或者非阻塞 I/O)与事件紧密结合的编程模式.这种模式与传统的同步式 I/O 线性的编程思路有很大的不同,因为控制流很大程度上要靠事件和回调函数来组织,一 ...

  7. Node.js 异步异闻录

    本文首发在个人博客:http://muyunyun.cn/posts/7b9fdc87/ 提到 Node.js, 我们脑海就会浮现异步.非阻塞.单线程等关键词,进一步我们还会想到 buffer.模块机 ...

  8. node js 异步运行流程控制模块Async介绍

    1.Async介绍 sync是一个流程控制工具包.提供了直接而强大的异步功能.基于Javascript为Node.js设计,同一时候也能够直接在浏览器中使用. Async提供了大约20个函数,包含经常 ...

  9. Node.js异步IO原理剖析

    为什么要异步I/O? 从用户体验角度讲,异步IO可以消除UI阻塞,快速响应资源 JavaScript是单线程的,它与UI渲染共用一个线程.所以在JavaScript执行的时候,UI渲染将处于停顿的状态 ...

随机推荐

  1. Ext.Net 破解

    在使用 Ext.Net 框架时,如果没有得到正版授权(安装密钥),在站点发布后,打开界面总是弹出一个窗口,提示没有授权,看着都头疼,难道一定要安装密钥吗?但还是有办法解决的,在研究时发现,页面中多了两 ...

  2. hadoop的live node为0

    1.重新格式化namenode cd ~ rm -rf name mkdir name rm -rf hadoop-2.7.2/logs/ mkdir hadoop-2.7.2/logs/ hadoo ...

  3. 关于javax.servlet.jsp.JspTagException: Don't know how to iterate over supplied "items" in &lt;forEach&gt;

    今天遇到这样一个异常: 严重: Servlet.service() for servlet jsp threw exceptionjavax.servlet.jsp.JspTagException: ...

  4. oracle 闪回技术

    oracle默认不启动闪回数据库 如果需要启动闪回数据库,数据库需要设置为归档模式,并启用恢复区. 1.查看是否启动闪回删除 SQL> show parameter recyclebin; NA ...

  5. Android基础总结(1)

    1.Android开发的特点 四大组件:活动(Activity).服务(Service).广播接收器(Broadcast Receiver).内容提供器(Content Provider).其中活动是 ...

  6. 华为OJ平台——完美数

    import java.util.Scanner; /** * * 完全数(Perfect number),又称完美数或完备数,是一些特殊的自然数. * 它所有的真因子(即除了自身以外的约数)的和(即 ...

  7. Java基础类库

    1 main方法      运行java程序的参数:   下面详细讲解main 方法为什么采用这个方法签名 1.public 修饰符:Java类由jvm调用,为了让jvm可以自由调用这个main()方 ...

  8. 使用.NET MVC框架项目开发流程(项目开发流程)

    MVC项目开发流程 整理需求,进行需求分析.项目设计. 整理数据项,建数据库做前期准备,并整理字典. 建立所需数据库表和视图和模型. 页面实现其初步功能(跳过逻辑后台代码),只是实现页面之间的跳转以及 ...

  9. JSON时间转换格式化

    通常JSON时间一般是这样的格式. 1 /Date(1436595149269)/ 通常我们用AJAX获取下来的JSON数据,如果有时间,都是这种格式的.其中,中间的一段数字"1436595 ...

  10. Oracle笔记 目录索引

    Oracle笔记 一.oracle的安装.sqlplus的使用 Oracle笔记 二.常用dba命令行 Oracle笔记 三.function .select Oracle笔记 四.增删改.事务 Or ...