CommonJs
JavaScript 是一个强大面向对象语言,它有很多快速高效的解释器。
然而, JavaScript 标准定义的 API 是为了构建基于浏览器的应用程序。并没有制定一个用于更广泛的应用程序 的标准库。
CommonJS 规范的提出,主要是为了弥补当前 JavaScript 没有标准库的缺陷。它的终极目标就是:提供一个类似 Python,Ruby 和 Java 语言的标准库,而不只是让 JavaScript 停留在小脚本程序的阶段。
用 CommonJS API 编写出的应用,不仅可以利用 JavaScript 开发客 户端应用,而且还可以编写以下应用。
•服务器端 JavaScript 应用程序。(nodejs)
•命令行工具。
•桌面图形界面应用程序。
CommonJS 就是模块化的标准,nodejs 就是 CommonJS(模块化)的实现。
Node.js模块化开发
Node 应用由模块组成,采用 CommonJS 模块规范
JS开发弊端
(1)文件与文件直接依赖关系不明确
(2)命名冲突
什么是模块化
(1)一个js文件就是一个模块
(2)每个模块都是一个独立的作用域,在这个而文件中定义的变量、函数、对象都是私有的,对其他文件不可见。
模块分类
核心模块(系统模块)
核心模块部分在 Node 源代码的编译过程中,编译进了二进制执行文件。在 Node 进程启动时,部分核心模块就被直接加载进内存中,所以这部分核心模块引入时,文件定位和 编译执行这两个步骤可以省略掉,并且在路径分析中优先判断,所以它的加载速度是最快的。
如:HTTP 模块 、URL 模块、Fs 模块都是 nodejs 内置的核心模块,可以直接引入使用。
第三方模块
由社区或个人提供,需要通过npm安装后使用
自定义模块(文件模块)
文件模块则是在运行时动态加载,需要完整的路径分析、文件定位、编译执行过程、 速度相比核心模块稍微慢一些,但是用的非常多。这些模块需要我们自己定义。
用户自定义模块
由开发人员创建的模块(JS文件)
基本使用:
1 创建模块
2 引入模块
注意:自定义模块的路径必须以./获取…/开头
// 加载模块
require('./a') // 推荐使用,省略.js后缀!
require('./a.js')
模块导出与导入
导出exports(exports方法导出)
var obj = {
get: function() {
console.log(111);
},
post: function() {
console.log(222);
}
}
exports.xxxx = obj;
导入require
//此时的request是在request.js中暴露的对象
const request = require("./moudle/request");
console.log(request);
导出exports(module.exports方法导出)
var obj = {
get: function() {
console.log(111);
},
post: function() {
console.log(222);
}
}
module.exports = obj;
导入require
//此时的request是在request.js中暴露的对象
const request = require("./moudle/request");
console.log(request);
require()谁,就会执行谁
exports与module.exports
module.exports是模块导出的另一种方式
当exports对象和module.exports对象指向的不是一个对象时,以module.exports为准。此时exports导出不在生效。
如果方法是独立的 建议使用exports
如果所以方法放在一个对象里面 建议使用module.exports
package.json的使用
在node_modules文件夹下的模块index.js文件可以直接引入,见下图:
此时index.js文件在jxios文件夹下 jxios文件夹在node_modules文件夹下
正常引入文件需要 写全引入路径,比如:
const jxios = require("./node_modules/jxios/index")
jxios.get();
但是因为在node_modules下,所以可以简写:
const jxios = require("index")
jxios.get();
如果在node_modelus下新建模块abcd并新建文件abcd.js,路径如下:
此时简写引入会不成立:
因为node.js会默认去寻找node_modules对应模块下的index.js文件,abcd模块下没有index.js文件,所以会报错。
可以用package.json文件解决:
此时在abcd模块下就有了package.json文件:
此时简写路径就可以运行:
因为此时node.js进入abcd模块下首先找到package.json文件 并查看主入口文件:
"main": "abcd.js",
这时abcd.js就相当于index.js,所以可以简写引入。
第三方模块(包)
Nodejs 中除了它自己提供的核心模块外,我们可以自定义模块,也可以使用第三方的 模块。Nodejs 中第三方模块由包组成,可以通过包来对一组具有相互依赖关系的模块进行统一管理。
完全符合 CommonJs 规范的包目录一般包含如下这些文件:
• package.json :包描述文件。
• bin :用于存放可执行二进制文件的目录。
• lib :用于存放 JavaScript 代码的目录。
• doc :用于存放文档的目录。
在 NodeJs 中通过 NPM 命令来下载第三方的模块(包):
npm(node package manager): node的第三方模块管理工具
下载:npm install 模块名称
下载到地方:npm自动创建一个文件夹便于存储,下载到命令行目录下
6.删除模块: npm uninstall 模块名称
本地安装:安装的当前项目中(库文件)
全局安装:安装到公共地方,项目都可使用(命令行工具)
npm介绍
npm 是世界上最大的开放源代码的生态系统。
我们可以通过 npm 下载各种各样的包, 这些源代码(包)我们可以在 https://www.npmjs.com 找到。
npm 是随同 NodeJS 一起安装的包管理工具,能解决 NodeJS 代码部署上的很多问题, 常见的使用场景有以下几种:
1.允许用户从 NPM 服务器下载别人编写的第三方包到本地使用。(silly-datetime)
2.允许用户从 NPM 服务器下载并安装别人编写的命令行程序(工具)到本地使用。 (supervisor)
3.允许用户将自己编写的包或命令行程序上传到 NPM 服务器供别人使用。
npm 命令详解
npm -v
查看 npm 版本
npm install Module Name
使用 npm 命令安装模块
如安装 jq 模块:npm install jquery
npm uninstall moudleName
卸载模块
npm list
查看当前目录下已安装的 node 包
npm info 模块
查看模块的版本
npm install jquery@1.8.0
指定版本安装
package.json文件
package.json定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、 许可证等元数据)
1、创建 package.json
npm init 或者 npm init –yes
2、package.json 文件
{
"name": "test",
"version": "1.0.0",
"description": "test",
"main": "main.js",
"keywords": ["test"],
"author": "wade",
"license": "MIT",
"dependencies": { "express": "^4.10.1" },
"devDependencies": {
"jslint": "^0.6.5"
}
}
3、安装模块并把模块写入 package.json(依赖)
npm install babel-cli --save-dev
npm install 模块 --save
npm install 模块 --save-dev
4、dependencies 与 devDependencies 之间的区别
–save-dev 和 –save 的区别
我们在使用npm install 安装模块或插件的时候,有两种命令把他们写入到 package.json 文件里面去,比如:
–save-dev 安装的 插件,被写入到 devDependencies 对象里面去
–save 安装的 插件 ,被写入到 dependencies 对象里面去
package.json 文件里面的 devDependencies 和 dependencies 对象区别呢
devDependencies 里面的插件只用于开发环境,不用于生产环境
dependencies 是需要发布到生产环境的。
假如用angularjs框架开发一个程序,开发阶段需要用到gulp来构建你的开发和本地运行环境。angularjs一定要放到dependencies里,因为以后程序到生产环境也要用。gulp则是你用来压缩代码,打包等需要的工具,程序实际运行的时候并不需要,所以放到devDependencies里就ok了。
"dependencies": {
"ejs": "^2.3.4",
"express": "^4.13.3",
"formidable": "^1.0.17"
}
^表示第一位版本号不变,后面两位取最新的
~表示前两位不变,最后一个取最新
*表示全部取最新
去掉前面符号:
"express": "4.13.3",
在下载多少次版本也不会变
淘宝镜像
淘宝 NPM 镜像是一个完整 npmjs.org 镜像,你可以用此代替官方版本(只读),同步频率目前为 10 分钟 一次以保证尽量与官方服务同步。
我们可以使用我们定制的 cnpm (gzip 压缩支持) 命令行工具代替默认的 npm:
npm install -g cnpm --registry=https://registry.npm.taobao.org
nrm
nrm(npm registry manager): npm下载地址切换工具
npm默认在国外,国内下载慢
步骤:
(1)npm install nrm -g
(2)查询下载地址 nrm ls
(3)切换npm下载地址 nrm use 下载地址名称
gulp模块挺大的,所以切换以后速度还是非常快的。
核心模块(系统模块)
fs模块
fs.stat 检测是文件还是目录
const fs = require("fs");
fs.stat('package.json', (err, data) => {
if (err) {
console.log(err);
}
console.log(`文件:${data.isFile()}`);
console.log(`文件:${data.isDirectory()}`);
})
fs.mkdir 创建目录
const fs = require("fs");
// path将创建的目录路径
// mode目录权限( 读写权限) 默认777
// callback 回调, 传递异常参数err
fs.mkdir('css', (err) => {
if (err) {
console.log(err);
return;
}
console.log('创建成功');
})
fs.writeFile 创建写入文件
const fs = require("fs");
/*
filename(String) 文件名称
data (String/Buffer) 将要写入的内容,可以是字符串,可以是buffer数据
options (Object) option数组对象,包含:
encoding (String) 可选值 默认'utf-8'
mode (Number) 文件读写权限,默认值438
flag (String) 默认值'w'
callback {Function} 回调,传递一个异常参数err
*/
fs.writeFile('./css/index.css', '你好eqeqeqeqe', (err) => {
if (err) {
console.log(err);
}
console.log('写入文件成功 ');
})
此时再写入新的 会覆盖原有写入的内容
fs.appendFile 追加文件
const fs = require("fs");
fs.appendFile('./css/base.css', 'h2{color:red}', (err) => {
if (err) {
console.log(err);
return;
}
console.log('appendFile 成功');
})
追加文件写入新的不会覆盖原有内容,会在原有内容后写入新内容
fs.readFile 读取文件
const fs = require("fs");
fs.readFile('./css/base.css', (err, data) => {
if (err) {
console.log(err);
return;
}
console.log(data);
console.log(data.toString()); //把Buffer 转化成string类型
})
fs.readdir 读取目录
const fs = require("fs");
fs.readdir('./css', (err, data) => {
if (err) {
console.log(err);
return;
}
console.log(data);
})
fs.rename 重命名
const fs = require("fs");
// 7.fs.rename 重命名
//功能: 1、 表示重命名 2、 移动文件
fs.rename('./css/index.css', './css/base.css', (err) => { //把css目录下index.css文件重命名为base.css
if (err) {
console.log(err);
return;
}
console.log('重命名成功');
})
fs.rename('./css/base.css', './html/base.css', (err) => { //把css目录下base.css文件 移动到html目录下
if (err) {
console.log(err);
return;
}
console.log('移动文件成功');
})
fs.rmdir 删除目录
const fs = require("fs");
fs.rmdir('./css', (err) => { //删除css目录
if (err) {
console.log(err);
return;
}
console.log('删除目录成功');
})
fs.unlink 删除文件
const fs = require("fs");
fs.unlink('./html/index.css', (err) => {
if (err) {
console.log(err);
return;
}
console.log('删除文件成功');
})
fa模块练习
1.判断服务器上面有没有upload目录。如果没有创建这个目录,如果有的话不做操作。 (图片上传)
const fs=require('fs');
var path='./upload';
fs.stat(path,(err,data)=>{
if(err){
//执行创建目录
mkdir(path);
return;
}
if(!data.isDirectory()){
//首先删除文件,再去执行创建目录
fs.unlink(path,(err)=>{
if(!err){
mkdir(path);
}else{
console.log('请检测传入的数据是否正确');
}
})
}
})
//创建目录的方法
function mkdir(dir){
fs.mkdir(dir,(err)=>{
if(err){
console.log(err);
return;
}
});
}
mkdirp模块 快速实现
/*
1、https://www.npmjs.com/package/mkdirp
2、cnpm i mkdirp --save / npm i mkdirp --save
3、var mkdirp = require('mkdirp');
4、看文档使用
*/
var mkdirp = require('mkdirp');
// mkdirp('./upload', function (err) {
// if (err) {
// console.error(err);
// }
// });
// mkdirp('./uploadDir');
mkdirp('./upload/aaa/xxxx', function (err) {
if (err) {
console.error(err);
}
});
2.wwwroot文件夹下面有images css js 以及index.html , 找出 wwwroot目录下面的所有的目录,然后放在一个数组中
1.改造for循环 递归实现:
const fs=require('fs');
//这是错误的写法 注意:fs里面的方法是异步
var path='./wwwroot';
var dirArr=[];
fs.readdir(path,(err,data)=>{
if(err){
console.log(err);
return;
}
for(var i=0;i<data.length;i++){ //for循环先执行完 i=4 不存在data[4]这个数据
fs.stat(path+'/'+data[i],(error,stats)=>{
if(stats.isDirectory()){
dirArr.push(data[i]);
}
})
}
console.log(dirArr);//打印结果为空 {}
})
console.log(dirArr); //打印结果为空 {}
//所以这是错误的写法 忽略了node.js异步
//定时器 异步例子
for(var i=0;i<3;i++){
//for循环先执行完 i=3
//然后执行定时器打印3个3
setTimeout(function(){
console.log(i);
},100)
}
//1、改造for循环 递归实现
//2、nodejs里面的新特性 async await
var path='./wwwroot';
var dirArr=[];
fs.readdir(path,(err,data)=>{
if(err){
console.log(err);
return;
}
(function getDir(i){
if(i==data.length){ //执行完成
console.log(dirArr);
return;
}
fs.stat(path+'/'+data[i],(error,stats)=>{
if(stats.isDirectory()){
dirArr.push(data[i]);
}
getDir(i+1)
})
})(0)
})
读取流
fs.createReadStream 从文件流中读取数据
const fs = require('fs');
// 创建一个可读流
var readStream = fs.createReadStream('./data/input.txt');
var count = 0;
var str = '';
readStream.on('data', (data) => {
str += data;
count++;
})
readStream.on('end', (data) => {
console.log(str);
console.log(count);
})
readStream.on('err', (data) => {
console.log(err);
})
写入流
fs.createWriteStream 写入文件
const fs = require('fs');
var str = '';
for (var i = 0; i < 20; i++) {
str += 'cnmcnmcnmCNM\n'
}
// 创建一个可写流
var writeStream = fs.createWriteStream('./data/output.txt')
writeStream.write(str);
//标记文件末尾
writeStream.end();
writeStream.on('finish', () => {
console.log('写入完成');
})
管道流
管道提供了一个输出流到输入流的机制。通常我们用于从一个流中获取数据并将数据传 递到另外一个流中。
const fs = require('fs');
// 创建一个可读流
var readStream = fs.createReadStream('./88.png');
// 创建一个可写流
var writeStream = fs.createWriteStream('./data/99.png')
// 管道读写操作
// 读取 88.png ,并将内容写入到 data目录下99.png
readStream.pipe(writeStream);
async/await
async 是“异步”的简写,而 await 可以认为是 async wait 的简写。所以应该很好理解 async 用于申明一个异步的 function ,而 await 用于等待一个异步方法执行完成。
async 是让方法变成异步,在终端里用 node 执行这段代码,你会发现输出了 Promise {‘Hello async’ },这时候会发现它返回的是 Promise。
function test1() {
return '123'
}
const test3 = test1();
console.log(test3); //123
async function test2() {
return '456'
}
const test4 = test2();
console.log(test4); //Promise { '456' }
await 在等待 async 方法执行完毕,其实 await 等待的只是一个表达式,这个表达式在官方 文档里说的是 Promise 对象,但是它也可以接受普通值。
注意:await 必须在 async 方法中 才可以使用,因为 await 访问本身就会造成程序停止堵塞,所以必须在异步方法中才可以使用。
function getData() {
return 'zhangsan';
}
async function testAsync() {
return 'Hello async';
}
async function test() {
const v1 = await getData();
const v2 = await testAsync();
console.log(v1, v2); //zhangsan Hello async
}
test();
async 会将其后的函数(函数表达式或 Lambda)的返回值封装成一个 Promise 对象,而 await 会等待这个 Promise 完成,并将其 resolve 的结果返回出来。
function findData() {
return new Promise(resolve => {
setTimeout(() =>
resolve("long_time_value"), 1000);
});
}
async function test() {
const v = await findData();
console.log(v); //long_time_value
}
test();