使用events.EventEmitter 控制Node.js 程序执行流程
使用events.EventEmitter 控制Node.js 程序执行流程
标题写的可能也不太对,大家领会精神;
Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台。
Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。
Node.js 异步编程的直接体现就是回调。
异步编程依托于回调来实现,但不能说使用了回调后程序就异步化了。
回调函数在完成任务后就会被调用,Node 使用了大量的回调函数,Node 所有 API 都支持回调函数。
例如,我们可以一边读取文件,一边执行其他命令,在文件读取完成后,我们将文件内容作为回调函数的参数返回。
这样在执行代码时就没有阻塞或等待文件 I/O 操作。这就大大提高了 Node.js 的性能,可以处理大量的并发请求。
Node.js 是单进程单线程应用程序,但是因为 V8 引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高。
Node.js 几乎每一个 API 都是支持回调函数的。
Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现。
Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数。
大意就是说:与大多数 代码从上至下线性执行的 程序不同,Node.js 程序不会“等”,
当程序执行到需要I/O执行时间的回调函数时,会主动略过等待,继续执行下面的代码;
因此就会出现一种弊端:一个特定函数的输入(参数),是数个回调函数的返回;
程序的执行机制会略过 对回调函数的等待,直接执行下面的特定函数;此时特定函数并没有等到回调函数返回的输入;
例子如下:
var fs = require("fs");
var array = [1, 2, 3, 4, 5];
var json = {};
for (let index = 0; index < array.length; index++) {
const element = array[index];
deal(element, function (ret) {
json[element] = ret;
console.log(json);
});
}
console.log(json);
function deal(num, callback) {
fs.readFile(num + '.txt', function (err, data) {
if (err) {
console.error(err);
callback(err);
} else {
callback(data.toString().trim());
}
});
}
Object {}
Object {1: "11111"}
Object {1: "11111", 5: "55555"}
Object {1: "11111", 3: "33333", 5: "55555"}
Object {1: "11111", 3: "33333", 4: "44444", 5: "55555"}
Object {1: "11111", 2: "22222", 3: "33333", 4: "44444", 5: "55555"}
回调函数要以数组里的内容作为文件名,读取文件中的数据作为返回值;
但程序不会等待文件读取完成,在没有一个文件读取完毕的情况下就执行了打印操作,输出了空对象;
如果想要按顺序线性执行文件读取,在读取完毕后打印输出,不仅浪费时间,而且一层套一层代码冗余,
还无法预估数组大小(回调函数个数)。
Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。
解决的办法是:Node.js 的事件驱动特性,让打印作为一个事件,在所有的回调函数执行完后,再触发打印操作;
var fs = require("fs");
var events = require('events');
var emitter = new events.EventEmitter();
var array = [1, 2, 3, 4, 5];
var count = 0;
var json = {};
for (let index = 0; index < array.length; index++) {
const element = array[index];
deal(element, function (ret) {
json[element] = ret;
console.log(json);
});
}
emitter.on('dataBack', function() {
count ++;
if(count == array.length){
console.log(json);
}
});
function deal(num, callback) {
fs.readFile(num + '.txt', function (err, data) {
if (err) {
console.error(err);
callback(err);
emitter.emit('dataBack');
} else {
callback(data.toString().trim());
emitter.emit('dataBack');
}
});
}
Object {1: "11111"}
Object {1: "11111", 4: "44444"}
Object {1: "11111", 3: "33333", 4: "44444"}
Object {1: "11111", 3: "33333", 4: "44444", 5: "55555"}
Object {1: "11111", 2: "22222", 3: "33333", 4: "44444", 5: "55555"}
Object {1: "11111", 2: "22222", 3: "33333", 4: "44444", 5: "55555"}
在程序中添加打印事件和事件触发,全部数据都集齐后再打印,
虽然还有count的锁不锁的问题存在,但实际的问题已然解决;
嗯嗯。
引用和改写的程序都来源于 Node.js 教程 | 菜鸟教程
不不不,一点也不推荐大家这么用。。。
太low了 用Promise吧
function run_a(num) {
return new Promise(function (resolve, reject) {
if (!isNaN(num)) {
resolve({ "number": num, "10*num": 10 * num })
} else {
reject({ "error": num + " is not a number!" })
}
});
}
var array = [1, 2, 3, 4, 5, 6, 7];
var function_array = [];
array.forEach(element => {
function_array.push(run_a(element));
});
console.log(function_array); // Array(7) [Promise, Promise, Promise, Promise, Promise, Promise, Promise]
Promise.all(function_array).then(function (data) {
console.log(JSON.stringify(data));
// [{"number":1,"10*num":10},{"number":2,"10*num":20},{"number":3,"10*num":30},{"number":4,"10*num":40},
// {"number":5,"10*num":50},{"number":6,"10*num":60},{"number":7,"10*num":70}]
}, function (data) {
console.log(data);
});
var array = [1, 2, 3, 4, 5, 'a', 7];
var function_array = [];
array.forEach(element => {
function_array.push(run_a(element));
}); Promise.all(function_array).then(function (data) {
console.log(JSON.stringify(data));
}, function (data) {
console.log(data); // {error: "a is not a number!"}
});
用Promise应对这种未知次数的并发等待问题可以说是很合适的了。
J.X.Duasonir
使用events.EventEmitter 控制Node.js 程序执行流程的更多相关文章
- 在Visual Studio上开发Node.js程序(2)——远程调试及发布到Azure
[题外话] 上次介绍了VS上开发Node.js的插件Node.js Tools for Visual Studio(NTVS),其提供了非常方便的开发和调试功能,当然很多情况下由于平台限制等原因需要在 ...
- 在Visual Studio上开发Node.js程序
[题外话] 最近准备用Node.js做些东西,于是找找看能否有Visual Studio上的插件以方便开发.结果还真找到了一个,来自微软的Node.js Tools for Visual Studio ...
- 一种简单的生产环境部署Node.js程序方法
最近在部署Node.js程序时,写了段简单的脚本,发觉还挺简单的,忍不住想与大家分享. 配置文件 首先,本地测试环境和生产环境的数据库连接这些配置信息是不一样的,需要将其分开为两个文件存储 到conf ...
- 在Visual Studio 2013 上开发Node.js程序
[题外话] 最近准备用Node.js做些东西,于是找找看能否有Visual Studio上的插件以方便开发.结果还真找到了一个,来自微软的Node.js Tools for Visual Studio ...
- 3.第一个Node.js程序:Hello World!
转自:http://www.runoob.com/nodejs/nodejs-tutorial.html 以下是我们的第一个Node.js程序: console.log("Hello Wor ...
- 玩儿转物联网IoT - 在Beagle Bone Black上运行node.js 程序
物联网(IoT)技术方兴未艾,智能手环,智能血压计,智能眼镜甚至智能鞋垫都开始进入我们的生活,各种智能设备层出不穷,世界已经到了一个"人有多大胆,地有多大产"的时代,不玩儿点物联网 ...
- Node.js如何执行cmd
最近正好因业务的一个需求需要研究如何根据vscode的插件名来下载对应的插件以解决之前将插件打包上传到服务器上面导致的延迟问题(插件体积小还好说,如果体积过大,即便是压缩打成zip包,如果同一时刻很多 ...
- Node.js程序在node-windows中不能运行
Node.js程序部分功能在命令行中运行良好,但在node-windows中不能运行,怎么回事? 答:路径问题. 请看如下的描述: My script runs fine on it's own, ...
- 调试 node.js 程序
调试 node.js 程序 在程序开发中,如何快速的查找定位问题是一项非常重要的基本功.在实际开发过程中,或多或少都会遇到程序出现问题导致无法正常运行的情况,因此,调试代码就变成了一项无法避免的工作. ...
随机推荐
- PymongoDB_study
import pymongo client = pymongo.MongoClient(host='localhost',port=27017)#连接数据库 #db = client.test#指定数 ...
- vue-cli项目在IE下运行钩子函数抛出异常“ReferenceError: “Promise”未定义"”的解决办法
兼容IE是个坑,低版本IE很多都没法跑起来 问题现象:vue-cli项目在IE下运行,会在钩子函数出现 ReferenceError: “Promise”未定义 解决办法: step1:安装最新的we ...
- C# 程序修改config文件后,不重启程序刷新配置ConfigurationManager
基本共识: ConfigurationManager 自带缓存,且不支持 写入. 如果 通过 文本写入方式 修改 配置文件,程序 无法刷新加载 最新配置. PS. Web.config 除外:Web. ...
- oracle报错 ORA-02290: 违反检查约束条件问题
场景: 使用plsql/developer 将原本要求非空的字段 改为可以为空 然后在插入数据的时候 报错改字段约束条件还起作用 解决方案: 首先查询该表的约束条件 select * from u ...
- Spring Cloud(Dalston.SR5)--Config 集群配置中心-加解密
实际应用中会涉及很多敏感的数据,这些数据会被加密保存到 SVN 仓库中,最常见的就是数据库密码.Spring Cloud Config 为这类敏感数据提供了加密和解密的功能,加密后的密文在传输给客户端 ...
- 带宽怎么算---Gbit/s
带宽怎么算---Gbit/s 信息来源: 计算方法: 带宽的实际应用:
- 【如皋OJ】1127:正整数N转换成一个二进制数
1127: 正整数N转换成一个二进制数 时间限制: 1 Sec 内存限制: 128 MB提交: 85 解决: 59[提交] [状态] [讨论版] [命题人:zhuzhigang] 题目描述 输入一 ...
- python基础知识13---函数对象、函数嵌套、名称空间与作用域、装饰器
阅读目录 一 函数对象 二 函数嵌套 三 名称空间与作用域 四 闭包函数 五 装饰器 六 练习题 一 函数对象 1 函数是第一类对象,即函数可以当作数据传递 #1 可以被引用 #2 可以当作参数传递 ...
- My Demos
Some elementary algorithms on discrete differential geometry http://www.cnblogs.com/yaoyansi/p/56350 ...
- gerrit中mysql配置
gerrit数据库使用mysql 进入gerrit数据库 mysql -ugerrit -p -h127.0.0.1 -P3307 密码为用户名加pass mysql> select * fro ...