nodejs学习之旅--第三天--ES6模块化规范以及commonjs规范--promise对象的使用以及异步终极解决方案async的使用

一、模块的使用

1.1、为什么要模块化(了解)

在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。
为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。(一个js文件就是一个模块)

使用模块有什么好处:

  • 最大的好处是大大提高了代码的可维护性。其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括 Node.js 内置的模块和来自第三方的模块。
  • 使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。

说重点:主要的原因是方便项目的开发和维护

1.2、模块规范的定义(了解)
  1. 一个js文件就是一个模块,模块的作用域是私有的,内部定义的变量或者函数,只在当前的文件(模块)可以使用
  2. 如果别人需要使用我们模块里面的东西,那么有两点要做(以CommonJS 的 Modules 规范: Node.js为例)
    1. 自己编写的模块,由于模块作用域是私有的,默认情况下,外部是没办法使用的;如果希望别人可以使用,则需要导出 exports 或者 module.exports。 导出的时候,以对象的方式进行导出
    2. 别人要使用某个模块,则需要先引入该模块,使用 require 引入,引入后需要使用一个变量来接收导入的对象。

对书写格式和交互规则的详细描述,就是模块定义规范(Module Definition Specification):

  • AMD 规范: Require.js
  • CMD 规范: Sea.js
  • CommonJS 的 Modules 规范: NodeJs
  • ES6 模块化规范 import … from …
1.3、模块化使用

导出数据方式一:

exports.num = num;
exports.sum = sum;
exports.Animal = Animal;

导出数据方式二:

// 通过module.exports 等于一个对象,来导出数据
// 对象可采用es6简化对象的写法
module.exports = {
    num,
    sum,
    Animal
};

导入数据:

// 注意1: 如果要使用某个模块里面的数据,则需要使用 require 关键字进行导入。
// 注意2:在导入用户自己开发的模块的时候,需要加上路径(1. 相对路径(多) 2. 绝对路径) 注意: ./ 必须写上
// 注意3:模块文件的扩展名(后缀名)可以写,也可以不写
// 注意4:导出的模块一般需要使用一个变量来接收,一般把接收的量定义为常量
// 注意5: 定义常量的名称和文件的名称保持一致(这个不是必须,大家都这么做)
const m1 = require("./modules/m1.js");

完整代码:

// m1.js中:    
let num = 10;
function sum(a, b) {
    return a+b
}

class Animal{
    constructor(){
        this.age=0
    }
}

// 导出数据方式1:
// exports.num = num;
// exports.sum = sum;
// exports.Animal = Animal;


// 导出数据方式2:
// 通过module.exports 等于一个对象,来导出数据
// 对象可采用es6简化对象的写法
module.exports = {
    num,
    sum,
    Animal
};


//01-模块的使用.js
const m1 = require("./modules/m1.js");


console.log(m1);   //{ num: 10, sum: [Function: sum], Animal: [Function: Animal] }
console.log(m1.sum(10, 20));
const obj = new m1.Animal();   //30
console.log(obj.age);   //0

二、模块里面this的指向问题

exports实际上是module.exports的引用,

在 nodejs 里面的 this 代表当前的这个模块,也就是 exports 对象

console.log(exports);   //{}
console.log(module.exports);  //{}
console.log(exports === module.exports);  //true  exports实际上是module.exports的引用

console.log('this', this); // this {}

console.log(this === exports);// true   // 在 nodejs 里面的 this 代表当前的这个模块,也就是 exports 对象  并且,交互模式下,没有exports这个对象
console.log(global === this );   //false    this不指向全局对象

三、nodejs常用内置模块

一般项目中模块分为3种,nodejs内置模块、自己书写的模块、第三方模块(使用一个专门的工具npm进行统一管理)

常用的内置模块如下:

  • fs :文件操作
  • http :网络操作
  • path :路径操作
  • querystring :查询参数解析
  • url :url 解析
const fs = require("fs");
const http = require('http');
const path = require('path');
const querystring = require('querystring');
const url = require('url');

nodejs内置模块的文档网址:http://nodejs.cn/api/

四、path内置模块

const path = require("path");

console.log(__dirname); // 当前执行的文件绝对路径,不包含文件名

console.log(__filename);  // 当前执行的文件绝对路径,包含文件名


let extname = path.extname( __filename );   // 获取扩展名(后缀名)
console.log(extname);

let baseName = path.basename( __filename );  // 获取文件名(包含后缀名)
console.log(baseName);

let dirname = path.dirname(__filename);   //获取目录(路径)
console.log(dirname);

let parse = path.parse(__filename);  //获取路径字符串的对象
console.log(parse);

//路径的拼接操作 join
// join 默认相对路径的拼接 ,以当前操作系统路径分割符进行拼接
let fullPath1 = path.join('path.js');
// fullPath1 = path.join(__dirname,'path.js'); //带目录
// fullPath1 = path.join(__dirname,'a','path.js'); //带多级目录
console.log(fullPath1);

五、Buffer数据类型

JavaScript 语言自身只有字符串数据类型,没有二进制数据类型。但在处理像文件流时(文件读写操作),必须使用到二进制数据。因此在 Node.js 中,定义了一个 Buffer 类,该类用来创建一个专门存放二进制数据的缓存区。说白了,Buffer 类似于一个整数数组。

下面是一张ASCII表:

img

创建buffer对象 :

let buf1 = Buffer.from([97, 98, 99]);  //根据一个数组创建 Buffer 对象
console.log(buf1);  //<Buffer 61 62 63> 以16进制存在buffer对象中
console.log(buf1.toString());

let buf2 = Buffer.from("nodejs");   //根据一个字符串创建 Buffer 对象
console.log(buf2);
console.log(buf2.toString());

let buf3 = Buffer.alloc(10);   // 创建了可以存放10个字符的buffer对象
buf3.write("abc");  //按照ASCII表的值,转16进制,存在buffer中
console.log(buf3);
console.log(buf3.toString());

// 总结: 以后看到 <Buffer .....  > 需要  toString()   才能看到里面的真实数据

六、fs文件系统模块

Node.js 的 API 内置有两个模块: path 和 fs ,我们使用 JavaScript 代码编写程序运行在 Node.js 环境中就可以操作文件

6.1、同步读取文件信息

同步读取:读取的时候,要等文件读取完毕后,才会执行后面的代码 (sync 同步)

const fs = require("fs");
const path = require("path");
let pathName = path.join(__dirname, 'hello.txt');

// const content = fs.readFileSync(pathName);   同步读取文件
// console.log(content);
// console.log(content.toString());

const content = fs.readFileSync(pathName, "utf-8");
console.log(content);

6.2、异步读取文件信息

不用等待文件读取完毕就会执行后面的代码。

思考:如何读到后面的数据

答:在读取文件的时候,传递一个回调函数callback,当读取完毕后,回调函数执行,读取后面的数据

const fs = require("fs");
const path = require("path");

let pathName = path.join(__dirname, "hello2.txt");
// console.log(file);
//参数1 要读取的文件
//参数2 设置读取到内容的编码,设置后读到的内容为字符串,如果不传则读到的数据为 buffer
//参数3 回调函数,读取完文件后执行的代码
fs.readFile(pathName, "utf-8",(error, data)=>{

    // console.log(error);
    // console.log(data);

   	if(error){
        console.log(error);
        return
    }

    console.log(data);
});
6.3、异步写入
const fs = require("fs");
const path = require("path");

let pathName = path.join(__dirname, "hello.txt");


fs.writeFile(pathName, "hello_write111", "utf-8",(error)=>{
    console.log("error");
    console.log("写完啦");
});
console.log("end");
6.4、几个常见方法
const fs = require("fs");
fs.renameSync(旧文件名, 新文件名);   //修改文件名
fs.readdirSync(__dirname);    //读取当前路径下的文件名列表

let str = "hello";
str.endsWith("he");   //true
str.startsWith("go");  //false
str.substring(2,4) //ll 左闭右开区间
str.substring(2) //llo  下标为2取到结束
6.5、小案例

需求:把当前文件夹的js文件的名字都添加前缀 [day03]

const fs = require("fs");
let nameList = fs.readdirSync(__dirname);

nameList.forEach(currFileName => {
    if(currFileName.endsWith(".js")){
        fs.renameSync(currFileName, `[day03]${currFileName}`)
    }
});

需求:把当前文件夹的名字都删除前缀 [day03]

const fs = require("fs");
let nameList = fs.readdirSync(__dirname);
let str1 = "[day03]"

nameList.forEach(currFileName => {
    if(currFileName.startsWith(str1)){
        fs.renameSync(currFileName, currFileName.substring(str1.length))
    }
});
6.6、思考题

// 需求:现在存在三个文件 1.txt(我) 2.txt(爱) 3.txt(nodejs)
// 每个文件里面有一个字符。使用:fs.readFile(异步) 顺序读取 1.txt 2.txt 3.txt 里面的内容,然后组成 我爱nodejs 把这个字符串写入 异步的写 到 data.txt 文件里面。

const fs = require("fs");
const path = require("path");

let pathName1 = path.join(__dirname,"files", "1.txt");
let pathName2 = path.join(__dirname,"files", "2.txt");
let pathName3 = path.join(__dirname,"files", "3.txt");
let pathName4 = path.join(__dirname,"files", "data.txt");


fs.readFile(pathName1,"utf-8",(error1, data1)=>{
    if(error1){
        console.log(error1);
        return
    }

    fs.readFile(pathName2,"utf-8",(error2, data2)=>{

        if(error2){
            console.log(error2);
            return
        }

        fs.readFile(pathName3,"utf-8",(error3, data3)=>{

            if(error3){
                console.log(error3);
                return
            }

            // console.log(data1+data2+data3);

            fs.writeFile(pathName4,data1+data2+data3,"utf-8",(error)=>{
                console.log(data1+data2+data3);
            })

        })
    })
});
6.7、回调地狱

在上面的题目中,操作之间是存在依赖性的,上一步依赖下一步的成功执行。但是操作又是通过异步api完成,则我们只能在回调函数里面编写,那么这个时候就会出现回调嵌套回调,俗称:回调地狱 Callback Hell。

后面我们使用promise来解决,async+await。

sync 同步

async 异步

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尤雨东

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值