NodeJS学习_模块与异步
2019-02-28
本内容参考《Node In Action》一书
模块
模块可以是单个文件,也可以是一个根目录有index.js
的文件目录(可以在package.json中指明别的文件名,不过何必呢)。
exports对象
模块的核心是exports
对象,该对象的属性暴露给外部使用。
外部通过require
请求外部模块,require
是同步操作,应减少出现次数,最佳实践是仅仅在程序开始时进行require
操作。
例子:
//currency.js
var canadianDollar=0.91;
function round2Dec(amount) {
return Math.round(amount * 100) / 100;
}
exports.canadianToUS = (canadian)=>{
return round2Dec(canadian * canadianDollar);
}
exports.USToCanadian = (us)=>{
return round2Dec(us/canadianDollar);
}
//test.js
var currency = require('./currency');
console.log('50 Ca to US:');
console.log(currency.canadianToUS(50));
console.log('50 Am to Ca: ');
console.log(currency.USToCanadian(50));
Module.exports对象
exports
只是对module.exports
对象的一个引用,所以不能直接重写exports对象,必要时(比如要让exports是一个构造函数)这样做:
module.exports = exports = xxx//自己定义的对象
require方法寻找模块的顺序
-
如果写了路径,直接搜路径。
-
如果只写了名字:
- 搜同一目录下的文件
- 搜同一目录下的
node_modules
目录 - 有父目录则进入父目录,回到第二步
- 若无父目录,进入环境变量NODE_PATH下的目录,回到第二步
- 抛出异常
package.json配置
- main:主文件,默认为根目录下的index.json
- name,version,description 自定义的名字、版本、描述
- dependencies:依赖
异步编程技术
EventEmitter
Node处理异步事件的核心类。
var EventEmitter = require('events').EventEmitter;
var channelEvent = new EventEmitter();
//绑定回调
channelEvent.on('join',(name)=>{
console.log('Welcome!'+name);
})
//发射事件触发回调
channelEvent.emit('join','qe')
//输出:Welcome!qe
异步的难题
作用域问题,因为异步不是马上触发,如果引用了外部变量,可能导致触发时变量的值已经变化了。
处理办法:匿名闭包函数
(arg)=>{
//do something with arg
}(arg);
异步逻辑的流程控制
-
保证异步逻辑的串行执行技巧:任务队列
function next(err, result) { if (err) throw err; var currentTask = tasks.shift(); //tasks是任务队列,没个task函数最后 //都调用了next() if (currentTask) { currentTask(result); } }
-
保证异步逻辑并行执行技巧:任务数组和检查函数
var completedTask=0; var tasks = [ //所有task都是函数,最后调用了checkIfComplete task1, task2, task3 ]; function checkIfComplete(){ completedTask++; if(completedTask==tasks.length){ console.log('complete') } } for(var task in tasks){ tasks[task](); }