NodeJS学习之异步编程
NodeJS -- 异步编程
NodeJS最大的卖点--事件机制和异步IO,对开发者并不透明
代码设计模式
var output = fn1(fn2('input'));
// Do something;
在异步方式下,由于函数执行结果不是通过返回值,而是通过回调函数传递,因此一般按以下方式编写代码:
fn2('input', function(output2) {
fn1(output2, function(output1) {
//Do something.
});
});
var len = arr.length,
i = 0;
for(;i < len; ++i) {
arr[i] = sync(arr[i]);
}
//All array items have processed.
若是异步执行,以上代码就无法保证循环结束后所有数组成员都处理完毕了,如果数组成员必须一个接一个串行处理,则按以下方式编写代码:
(function next(i, len, callback) {
if(i < len) {
async(arr[i], function(value) {
arr[i] = value;
next(i + 1, len, callback);
});
} else {
callback();
}
}(0, arr.length, function() {
// All array items have processed.
}));
可以看到,在异步函数执行一次并返回执行结果后才传入下一个数组成员并开始下一轮执行,直到所有数组成员处理完毕后,通过回调的方式触发后续代码执行。
若数组成员可以并行处理,但后续代码仍然需要所有数组成员处理完毕后才能执行的话,则异步代码调整成以下形式:
(function(i, len, count, callback) {
for(;i < len; ++i) {
(function(i) {
async(arr[i], function(value) {
arr[i] = value;
if(++count === len) {
callback();
}
});
}(i));
}
}(0, arr.length, 0, function() {
//All array items have processed.
}));
以上代码并行处理所有成员,并通过计数器变量来判断什么时候所有数组成员都处理完毕了
function async(fn, callback) {
// Code execution path breaks here.
setTimeout(function() {
callback(fn());
}, 0);
}
try {
async(null, function(data) {
// Do something.
});
} catch(err) {
console.log('Error: %s', err.message);
}
-----------------------Console----------------------------
E:\Language\Javascript\NodeJS\try_catch.js:25
callback(fn());
^
TypeError: fn is not a function
at null._onTimeout (E:\Language\Javascript\NodeJS\try_catch.js:25:18)
at Timer.listOnTimeout (timers.js:92:15)
因为代码执行路径被打断了,我们就需要在异常冒泡到断点之前用try语句把异常捕获注,并通过回调函数传递被捕获的异常,改造:
function async(fn, callback) {
// Code execution path breaks here.
setTimeout(function() {
try {
callback(null, fn());
} catch(err) {
callback(err);
}
}, 0);
}
async(null, function(err, data) {
if(err) {
console.log('Error: %s', err.message);
} else {
// Do something
}
})
----------------------Console----------------------
Error: fn is not a function
function main(callback) {
// Do something.
asyncA(function(err, data) {
if(err) {
callback(err);
} else {
// Do something.
asyncB(function(err, data) {
if(err) {
callback(err);
} else {
// Do something.
asyncC(function(err, data) {
if(err) {
callback(err);
} else {
// Do something.
callback(null);
}
});
}
});
}
});
}
main(function(err) {
if(err) {
// Deal with exception.
}
});
回调函数已经让代码变得复杂了,而异步之下的异常处理更加剧了代码的复杂度,幸好,NodeJS提供了一些解决方案。
域
process.on('uncaughtException', function(err) {
console.log('Error: %s', err.message);
});
setTimeout(function(fn) {
fn();
});
------------------------Console--------------------
Error: fn is not a function
function async(req, callback) {
// Do something.
asyncA(req, function(err, data) {
if(err) {
callback(err);
} else {
// Do something.
asyncB(req, function(err, data) {
if(err) {
callback(err);
} else {
// Do something.
asyncC(req, function(err, data) {
if(err) {
callback(err);
} else {
// Do something.
callback(null, data);
}
});
}
});
}
});
}
http.createServer(function(req, res) {
async(req, function(err, data) {
if(err) {
res.writeHead(500);
res.end();
} else {
res.writeHead(200);
res.end();
}
});
});
以上将请求对象交给异步函数处理,再根据处理结果返回响应,这里采用了使用回调函数传递异常的方案,因此async函数内部若再多几个异步函数调用的话,代码就更难看了,为了让代码好看点,可以在没处理一个请求时,使用domain模块创建一个子域,在子域内运行的代码可以随意抛出异常,而这些异常可以通过子域对象的error事件统一捕获,改造:
function async(req, callback) {
// Do something.
asyncA(req, function(data) {
// Do something.
asyncB(req, function(data) {
// Do something.
asyncC(req, function(data) {
// Do something.
callback(data);
});
});
});
}
http.createServer(function(req, res) {
var d = domain.create();
d.on('error', function() {
res.writeHead(500);
res.end();
});
d.run(function() {
async(req, function(data) {
res.writeHead(200);
res.end(data);
});
});
});
注:JS的throw...tyr...catch异常处理机制并不会导致内存泄漏和使程序执行出乎意料,而是因为NodeJS并不是纯粹的JS,NodeJS里大量的API内部是用C/C++实现的,因此NodeJS程序运行过程中,代码执行路径穿梭于JS引擎内外部,而JS异常抛出机制可能打断正常代码的执行流程,导致C/C++部分的代码表现异常,进而导致内存泄漏。
因此,使用uncaughtException或domain捕获异常,代码执行路径里涉及到了C/C++部分的代码时,若不能确定是否会导致内存泄漏等问题,最好在处理完异常后重启程序比较妥当,而使用try语句捕获的异常一般是JS本身的异常,不用担心上述问题
NodeJS学习之异步编程的更多相关文章
- nodejs学习笔记 —— 异步编程解决方案
在js或者node编程中,由于异步的频繁和广度使用,使得回调和嵌套的深度导致编程的体验遇到一些挑战,如果写出优雅和好看的代码,本文主要针对异步编程的主流方案做一些总结 1.事件发布/订阅模式 事件监听 ...
- 深入理解nodejs中的异步编程
目录 简介 同步异步和阻塞非阻塞 javascript中的回调 回调函数的错误处理 回调地狱 ES6中的Promise 什么是Promise Promise的特点 Promise的优点 Promise ...
- nodejs之async异步编程
1.什么是异步编程? 异步编程是指由于异步I/O等因素,无法同步获得执行结果时, 在回调函数中进行下一步操作的代码编写风格,常见的如setTimeout函数.ajax请求等等. 示例: for (v ...
- 《C#并发编程经典实例》学习笔记—异步编程关键字 Async和Await
C# 5.0 推出async和await,最早是.NET Framework 4.5引入,可以在Visual Studio 2012使用.在此之前的异步编程实现难度较高,async使异步编程的实现变得 ...
- 09-Node.js学习笔记-异步编程
同步API,异步API 同步API:只有当前API执行完成后,才能继续执行下一个API console.log('before'); console.log('after'); 异步API:当前API ...
- Java8学习之异步编程
异步编程 所谓异步其实就是实现一个无需等待被调用函数的返回值而让操作继续运行的方法 创建任务并执行任务 无参创建 CompletableFuture<String> noArgsFutur ...
- 学习Promise异步编程
JavaScript引擎建立在单线程事件循环的概念上.单线程( Single-threaded )意味着同一时刻只能执行一段代码.所以引擎无须留意那些"可能"运行的代码.代码会被放 ...
- 借助Q.js学习javascript异步编程。
金字塔式 //add1 function step1(n, callback) { setTimeout(function(){ callback.call(null, n + 1); }, 100) ...
- nodejs 学习三 异步和同步
同步函数 for (let i = 0; i < 10; i ++) { setTimeout(() => { console.log(`${i} ______ ${new Date}`) ...
随机推荐
- AS:加载新版本的SWF文件。
方案一: 文件名+版本号,区别对待不同的版本控制,有设定值后会加上_v_x的后缀名.如:加载主文件 main.swf, 被命名为:Main_v_60.swf . 方案二: loader.load(ne ...
- Notepad++配置Python运行环境
转自:http://www.cnblogs.com/zhcncn/p/3969419.html Notepad++配置Python开发环境 1. 安装Python 1 下载 我选择了32位的2.7 ...
- T4模板语法
T4,即4个T开头的英文字母组合:Text Template Transformation Toolkit. T4文本模板,即一种自定义规则的代码生成器.根据业务模型可生成任何形式的文本文件或供程序调 ...
- Java数据结构之线性表
从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的 ...
- 从Windows 服务器通过sync向Linux服务器定时同步文件
本文解决的是Windows 下目录及文件向Linux同步的问题,Windows向 Windows同步的请参考:http://www.idcfree.com/article-852-1.html 环境介 ...
- JavaScript模块化开发一瞥
对于那些正在构建大型应用程序,而对JavaScript不甚了解的开发者而言,他们最初必须要面对的挑战之一就是如何着手组织代码.起初只要在标记之间嵌入几百行代码就能跑起来,不过很快代码就会变得一塌糊涂… ...
- plupload上传插件在SpringMVC中的整合
前言:近期在给学院的站点做一个加入附件的功能,首先到了某某邮箱看了一下.简单有用.可是是flash做的,无法拷贝.就仅仅好上网找插件了.经过筛选.最终找到plupload这款插件(其实有的编辑器自带加 ...
- Ajax缓存解决办法
解决办法有如下几种: 1.在服务端加 header("Cache-Control: no-cache, must-revalidate");(如php中) 2.在aja ...
- php内核探索
http://www.nowamagic.net/librarys/veda/special/PHP%E5%86%85%E6%A0%B8%E6%8E%A2%E7%B4%A2 关注PHP 源代码 Zen ...
- iOS (UIButton封装)仿糯米首页缩放“按钮”效果
前言 过年期间,少不了各种聚会,当下聚会大多数情况下自然是团购,然后就是用各种APP...使用度娘糯米时(不是广告,不是广告,不是广告!),偶然注意到了它的首页中一个有意思的效果,就是那些“按钮”点击 ...