一、Node开发概述
1、服务器端开发要做的事情
- 实现网站业务逻辑
- 数据的增删改查
2、全局对象
在浏览器中全局对象是window,而在node中全局对象是global。
image.png二、Node.js模块化开发
1、非模块化js开发的弊端
非模块化开发可能会存在文件依赖比较复杂、命名冲突的问题。
2、node模块化开发规范
2.1、模块导出与导入
- 一个js文件就是一个模块,模块内部定义的变量和函数默认情况下外部无法访问
- 模块内部可以使用exports对象进行成员导出,通过require方法导入其他模块。(模块的后缀名可以省略)
2.2、模块的另一种使用
module.exports
导出模块,require导入模块。
区别:与上一个方法的区别在于exports
是module.exports
的别名(地址引用关系),导出对象最终以module.exports
为准。
module对象中包含了exports对象,而exports只是已用了module.exports对象。
用法区别:如果模块返回的函数或变量不止一个,那它可以通过设定exports
对象的属性来指明它们。但如果模块只返回一个函数或变量,则可以设定module.exports
属性。
require是node中少数几个同步I/O操作之一。
3、node_module文件夹
Node中有一个独特的模块引入机制,可以不必知道模块在文件系统中的具体位置。这个机制就是使用node_modules目录。 node寻找模块的机制是:
image.png在模块目录中的模块主文件必须被命名为index.js ,除非你在这个目录下一个叫package.json的文件里特别指明。 package.json文件中有一个名为main的键,指明模块目录内主文件的路径。
image.png
三、异步编程技术
在Node的世界里流行两种响应逻辑管理方式:回调和事件监听。
回调通常用来定义一次性响应的逻辑。(之前写的读取文件操作就是用了回调)
事件监听器,本质上也是一个回调,不同的是,它跟一个概念实体(事件)相关联,可以重复响应。
1、创建事件发射器
var EventEmitter = require('events').EventEmitter;
var channel = new EventEmitter();
channel.on('join',function(id, client){
console.log("welcome!");
});
触发事件:
channel.emit('join', id, client);
移除监听:removeListener(事件名)
改变监听器最大数量:为了增加能够附加到事件发射器上的监听器数量, 不让Node在监听器数量超过10个时向你发
出警告,可以用setMaxListeners方法
2、扩展事件监听器
扩展事件发射器需要三步:
-
声明自定义类的构造器;
-
自定义类继承事件发射器对象;
-
扩展这些行为。
var events = require('events'),util = require ('util');
function watcher (watchDir, processedDir){
this.watchDir=watchDir;
this.processedDir = processedDir ;
}
// node 自带的工具类的函数inherits,可以方便地实现继承
util.inherits(Watcher, events.EventEmitter) ;
3、异步开发的问题
如果在执行一步函数后修改函数内部调用的外部变量,最后这个变量的值可能无法预测。我们可以利用函数闭包解决这个问题。
在闭包中,将外部变量转换成匿名函数的参数,也就是闭包内部的局部变量(与外部变量无关),这样即使修改这个变量,函数也不会受到影响。
function asyncFunction(callback){
setTimeout(callback,200);
}
var color = 'blue ' ;
(function (color){
asyncFunction(function(){
console.log('The color is ' + color) ;
});
})(color) ;
color = 'green';
4、异步逻辑的顺序化
有些异步函数之间是相互关联的,一个异步函数的执行可能依赖上一个或多个异步函数执行的结果。这个时候我们需要让异步函数顺序执行。这个概念被称为流程控制,分为串行和并行。
image.png4.1、串行流程实现
利用现有包:Nimble 。可以通过npm安装,使用只需要将一个函数数组传递过去就可以顺序执行异步函数:
var flow=require('nimble');
flow.series([
function (callback){
setTimeout(function (){
console.log('I execute first.');
callback() ;
},1000);
},
function (callback){
setTimeout(function(){
console.log('工 execute next.');
callback();
},500) ;
},
function (callback){
setTimeout(function(){
console.log('l execute last.');
callback();
}, 100) ;
}
]);
其他流程控制工具:Step、Seq等
自定义函数实现:
function next (err, result){
if(err) throw err;
// 删除数组中第一个元素,并将删除的元素返回
// tasks 是一个任务函数数组
var currentTask = tasks.shift();
if(currentTask){
currentTask(result);
}
4.2、并行流程实现
每个任务并行执行,在回调函数中调用所有函数执行完成后调用需要执行的操作函数,当执行完成函数数量达到总任务数后,视为执行完成:
function checkIfComplete(){
// 每个函数的回调函数中都会调用一遍
completedTasks++;
if(completedTasks == tasks. length){
for (var index in wordcounts) {
console.log (index +': ' + wordcounts[index]);
}
}
网友评论