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方法寻找模块的顺序

  1. 如果写了路径,直接搜路径。

  2. 如果只写了名字:

    1. 搜同一目录下的文件
    2. 搜同一目录下的node_modules目录
    3. 有父目录则进入父目录,回到第二步
    4. 若无父目录,进入环境变量NODE_PATH下的目录,回到第二步
    5. 抛出异常

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);

异步逻辑的流程控制

  1. 保证异步逻辑的串行执行技巧:任务队列

    function next(err, result) { 
        if (err) throw err; 
        var currentTask = tasks.shift(); 
        //tasks是任务队列,没个task函数最后
        //都调用了next()
        if (currentTask) 
        { 
            currentTask(result);
        } 
    }
    
  2. 保证异步逻辑并行执行技巧:任务数组和检查函数

    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]();
    }