node.js 学习笔记

NodeJS架构组成

  • Node.js是⼀个构建在Chrome浏览器 V8引擎上的JavaScript运⾏环境,使⽤单线程、事件驱动、⾮阻塞I/O的⽅式实现了⾼并发请求, libuv 为其提供了异步编程的能
  • ⼒。
  • Node.js标准库:由JavaScript编写的,也就是我们使⽤过程中直接能调⽤的API,在源码中的 lib⽬录下可以看到,诸如 http、fs、events 等常⽤核⼼模块。
  • Node bindings: 可以理解为是JavaScript与C/C++库之间建⽴连接的桥 ,通过这个桥,底层实现的C/C++库暴露给JavaScript环境,同时把 js传⼊V8 , 解析后交给 libuv
  • 发起⾮阻塞 I/O , 并等待事件循环调度;
  • V8: Google推出的Javascript虚拟机,为Javascript提供了在⾮浏览器端运⾏的环境;
  • libuv:为Node.js提供了跨平台,线程池,事件池,异步I/O 等能⼒,是Nodejs之所以⾼效的主要原因;
  • C-ares:提供了异步处理DNS相关的能⼒;

    http_parser、OpenSSL、zlib等:提供包括http解析、SSL、数据压缩等能⼒;

 

 

1.fs文件系统模块


1.1读取指定文件中的内容

//导入fs模块,来操作文件。
const fs=require('fs')

//调用fs.readFile()方法读取文件
//参数1:读取文件的存放路径
//参数2. 读取文件时候采用的编码格式,一般默认指定utf8
//参数3. 回调函数
fs.readFile('./files/a.txt','utf8',function(err,dataStr){
//    2.1 打印失败结果
// 读取成功null
    console.log(err);
    console.log('----');
    // 打印成果结果
    console.log(dataStr);
})

判断是否读取成功

//导入fs模块,来操作文件。
const fs=require('fs')

//调用fs.readFile()方法读取文件
//参数1:读取文件的存放路径
//参数2. 读取文件时候采用的编码格式,一般默认指定utf8
//参数3. 回调函数
fs.readFile('./files/a.txt','utf8',function(err,dataStr){
if(err){
    return console.log('读取文件失败!',+err.message);
}
console.log('读取文件成功!'+dataStr);
})

 

 1.2 向指定文件写入内容

// 导入fs文件系统模板
const fs=require('fs')
//2.调用fs.writeFile()方法,写入文件的内容
// 参数1:表示文件存放的路径
// 参数2:表示要写入的内容
// 参数3:回调参数

fs.writeFile('./files/a.txt','abcd',function(err){
    // 写入成功err 为null
    console.log(err);
})

判断是否写入成功

// 导入fs文件系统模板
const fs=require('fs')
//2.调用fs.writeFile()方法,写入文件的内容
// 参数1:表示文件存放的路径
// 参数2:表示要写入的内容
// 参数3:回调参数

fs.writeFile('./files/a.txt','abcd',function(err){
    // 写入成功err 为null
    if(err){
      return console.log('文件写入失败',err.message);
    }
    console.log('文件写入成功');
})

1.3 路径处理问题 

const fs=require('fs')

// __dirname当前文件所在目录
fs.writeFile(__dirname+'/files/a.txt','abcd',function(err){
    // 写入成功err 为null
    if(err){
      return console.log('文件写入失败',err.message);
    }
    console.log('文件写入成功');
})

 1.4.path模块

 path.join()方法

const path=require('path')
const fs =require('fs')
// 注意   .../会抵消前面的路径
// const pathStr =path.join('/a','/b/c','../','./d','e')
// console.log(pathStr);
fs.readFile(path.join(__dirname,'./files/a.txt'),'utf8',function(err,dataStr){
if(err){
    return console.log('读取文件失败!',+err.message);
}
console.log('读取文件成功!'+dataStr);
})

 

 path.basename

 path.extname

const path =require('path')
//定义文件的存放路径
const fpath='/a/b/c/index.html'
const ftext=path.extname(fpath)
console.log( ftext);//.html

2.htttp模块

服务器相关概念

ip

 域名

 端口

创建基本web服务器

// 1.导入http模块
const http =require('http')
// 2.创建web服务器实例
const server =http.createServer()
// 3.为服务器实力绑定 request 事件,监听客户端的请求
server.on('request',function(req,res){
    console.log('Someone visit our web serve.');
 
})
// 4启动服务器
server.listen(8080,function(){
    console.log('serve running at http://127.0.0.1:8080');
})

 

rep请求对象

var http = require('http');
http.createServer(function (request, response) {
       // 发送 HTTP 头部 4    // HTTP 状态值: 200 : OK5    // 内容类型: text/plain6    
       response.writeHead(200, {'Content-Type': 'text/plain'});   // 发送响应数据 "Hello World"8   
        response.end('Hello World\n');9}).listen(8888);
        console.log('Server running at http://127.0.0.1:8888/')

接下来就可以在⻚⾯上访问http://127.0.0.1:8888/这个⽹址。访问之后获取到该服务器给的响应“Hello World

 3.模块化

CommonJS模块化

 

 

CommonJS规定,每个⽂件就是⼀个模块,有⾃⼰的作⽤域。在⼀个⽂件⾥⾯定义的变量、函数、类,都是私有的,对其他⽂件不可⻅。每个模块内部, module 变量代表当前模块。这个变量是⼀个对象,它的 exports 属性(即 module.exports )是对外的接⼝。加载某个模块,其实是加载该模块的 module.exports 属性。 require

⽅法⽤于加载模块。

 module对象

每个模块内部,都有⼀个 module 对象,代表当前模块。

 导出模块

module.exports = {
 name: 'tom',
  sayHello() {
 console.log("hello");
  },
};

exports 和 module.exports 的使⽤

默认情况下:module.exports===exports为true,相当于如下内容:

module.exports = {}

exports = module.exports;

require引⼊的对象本质上是module.exports。这就产⽣了⼀个问题,当

module.exports和exports指向的不是同⼀块内存时,exports的内容就会失效。

如果要对外暴露属性或⽅法,就⽤ exports 就⾏,要暴露对象(包含了很多属性和⽅法),就⽤ module.exports。

 导⼊模块

在 Node.js 中,引⼊⼀个模块⾮常简单,如下我们创建⼀个 module1Test.js ⽂件并引⼊ module 模块,代码如下:

let obj = require('./modules.js')
console.log(obj);
obj.sayHello()

1. 所有代码都运⾏在模块作⽤域,不会污染全局作⽤域。

2. 模块可以多次加载,但是只会在第⼀次加载时运⾏⼀次,然后运⾏结果就

被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运⾏,必

须清除缓存。

3. 模块加载的顺序,按照其在代码中出现的顺序。

 

 

 require⽅法

require引⼊的对象本质上是module.exports。

 NodeJS使⽤CommonJS模块规范,内置的 require 命令⽤于加载模块⽂件。 require

命令的基本功能是,读⼊并执⾏⼀个JavaScript⽂件,然后返回该模块的exports对象。如果没有发现指定模块,会报错。 需要注意的是:

 1. 如果参数字符串以“/”开头,则表示加载的是⼀个位于绝对路径的模块⽂件。

⽐如, require('/home/marco/foo.js') 将加载 /home/marco/foo.js 。

2. 如果参数字符串以“./”开头,则表示加载的是⼀个位于相对路径(跟当前执⾏脚

本的位置相⽐)的模块⽂件。⽐如, require('./circle') 将加载当前脚本

同⼀⽬录的circle.js 。

3. 如果参数字符串不以“./“或”/“开头,则表示加载的是⼀个默认提供的核⼼模块

(位于Node的系统安装⽬录中),或者⼀个位于各级node_modules⽬录的已安装模块(全局安装或局部安装)。

 4.ECMAScript模块

在ES6中每⼀个模块即是⼀个⽂件,在⽂件中定义的变量,函数,对象在外部是⽆法获取的。如果你希望外部可以读取模块当中的内容,就必须使⽤export来对其进⾏暴露(输出)。

export命令规定的是对外的接⼝,必须与模块内部的变量建⽴⼀⼀对应关系,也就是说外部接⼝需要⽤这个接⼝名来引⽤。

5 .异常处理

Node是单线程运⾏环境,⼀旦抛出的异常没有被捕获,就会引起整个进程的崩溃。所以, Node的异常处理对于保证系统的稳定运⾏⾮常重要。

 ⼀般来说,Node有如下三种⽅式,会产⽣异常。

使⽤throw语句抛出⼀个错误对象,即抛出异常。

将错误对象传递给回调函数,由回调函数负责发出错误。通过EventEmitter接⼝,发出⼀个error事件。

 解决⽅案

try-catch

⼀般来说,Node只在很少场合才⽤try/catch语句,⽐如使⽤ JSON.parse 解析JSON

⽂本。这个结构⽆法捕获异步运⾏的代码抛出的异常。

// 可以捕获到异常
try {
     console.log(a); 
     } catch (err) {
         //这⾥的代码会有执⾏
          console.log("捕获异常:",err); }
          console.log('end');  //先打印捕获到的异常,再end

 6url模块

url.parse()

将url字符串地址转换为URL对象 

const url = require('url')
const myURL = url.parse('https://user:pass@sub.example.com:8080/p/a/t/h?query=string#hash');
console.log(myURL);

结果

Url {  protocol: 'https:', 
 slashes: true, 
 auth: 'user:pass',
  host: 'sub.example.com:8080', 
 port: '8080',  
hostname: 'sub.example.com', 
 hash: '#hash', 
 search: '?query=string', 
 query: 'query=string',  
pathname: '/p/a/t/h',
  path: '/p/a/t/h?query=string', 
 href: 'https://user:pass@sub.example.com:8080/p/a/t/h?query=string#hash'14
}

url.format()

构建⼀个URL字符串

const url = require('url');
let result = url.format({
  protocol: 'https', 4
 hostname: 'example.com', 
  pathname: '/some/path', 
 query: {
   page: 1,
   format: 'json'
}
});
console.log(result);
// => 'https://example.com/some/path?page=1&format=json'

url.resolve(from,to)

合并url字符串

const url = require('url');
console.log(url.resolve('/one/two/three', 'four')); 
// '/one/two/four' 
console.log(url.resolve('http://example.com/', '/one')); // 'http://example.com/one' console.log(url.resolve('http://example.com/one', '/two')); // 'http://example.com/two'

 url.hash

获取或设置URL中hash值

const myURL = new URL('https://example.org/foo#bar'); 
console.log(myURL.hash);// Prints #bar3myURL.hash = 'baz'; 
console.log(myURL.href);// Prints https://example.org/foo#baz

 7:querystring模块

该模块⽤来处理查询字符串。

 querystring.parse(str[, sep[, eq[, options]]])

将查询字符串解析为⼀个对象

const querystring = require('querystring');
let qs = "name=terry&age=12&gender=male" 
console.log(querystring.parse(qs));
// { name: 'terry', age: '12', gender: 'male' }

 querystring.stringify(obj[, sep[, eq[, options]]])

将⼀个对象序列化为查询字符串

const querystring = require('querystring');
let qs_obj = { name: 'terry', age: '12', gender: 'male' }; console.log(querystring.stringify(qs_obj)) 
// name=terry&age=12&gender=male

 querystring.escape()

对查询字符串进⾏编码

const querystring = require('querystring');
console.log(querystring.escape('name=张三&age=12'));
//name%3D%E5%BC%A0%E4%B8%89%26age%3D12

 querystring.unescape()

对查询字符串进⾏解码

const querystring = require('querystring');
console.log(querystring.unescape('name%3D%E5%BC%A0%E4%B8%89%26age%3D12'));
//name=张三&age=12

 8.path模块

提供了⼀系列解析路径的⼯具

path.basename(path[, ext]))

返回路径中最后⼀部分。参数path为路径字符串,ext为可选的⽂件扩展名。

path.dirname(path)

返回路径中代表⽂件夹的部分

path.extname(path)

 9util模块

util.callbackify()

将 async 异步函数(或者⼀个返回值为 Promise 的函数)转换成遵循异常优先的回调⻛格的函数,例如将 (err, value) => ... 回调作为最后⼀个参数。 在回调函数中,第⼀个参数为拒绝的原因(如果 Promise 解决,则为 null ),第⼆个参数则是解决的值。

const util = require('util'); 
async function fn() {
 return 'hello world'; 
 //return a;
}
//fn().then().catch((err)=>{})
const callbackFunction = util.callbackify(fn); 
callbackFunction((err, value) => {
  if (err) throw err;
  console.log(value); });

10.宏任务与微任务

宏任务

Event Loop 有⼀个或多个任务(宏任务)队列,当 执⾏栈 为空时,会从任务队列⾥获取任务,加⼊到执⾏栈中,这⾥的任务就是宏任务。如下都是宏任务:

Events---事件交互

Callbacks---回调函数

Using a resource(I/O)----使⽤资源,包括ajax

Reacting to DOM manipulation---对DOM操作的反应

script(整体script也被看做是⼀个宏任务,所以⼀开始整个script脚本都被推⼊宏任务中,事件循环是从第⼀个宏任务开始的)

setTimeout()/setInterval()/setImmediate()---定时器

requestAnimationFrame()---制作动画的⼀个函数

 微任务

每个 Event Loop 有⼀个微任务队列,同时有⼀个 microtask checkpoint ,即每执⾏完成⼀个宏任务后,就会 check 微任务。所以,当某个宏任务执⾏完成后,会先执⾏微任务队列,执⾏完成后,再次获取新的宏任务。这⾥微任务相当于插队操作!!

process.nextTick()

Promise(aync/await)

Object.observe(已过期,是监听对象变化的⼀个函数)MutationObserver(监听dom树变化)

 

 宏任务:包括整体代码script(可以理解为外层同步代码)、settimeout、

setInterval、i/o、ui render、异步ajax、⽂件操作等

微任务:promise、Object.observe(⽤来实时监测js中对象的变化)、

MutationObserver(监听DOM树的变化)

 执⾏顺序

先执⾏同步代码,遇到异步宏任务则将异步宏任务放⼊宏任务队列中,遇到异步微任务则将异步微任务放⼊微任务队列中,当所有同步代码执⾏完毕后,再将异步微任务从队列中调⼊主线程执⾏,微任务执⾏完毕后。再将异步宏任务从队列中调⼊主线程执⾏,⼀直循环直⾄所有任务执⾏完毕(事件循环EventLoop)。

 每⼀个宏任务执⾏完之后,都会检查是否存在待执⾏的微任务;如果有,则执⾏完所有微任务之后,再继续执⾏下⼀个宏任务。

 

 

//setTimeout第⼆个参数可以省略,默认为0
setTimeout(function () {
  console.log('1');
})
new Promise(function (resolve) {
  console.log('2');
  resolve();
}).then(function () {
 console.log('3');
})
console.log('4');
//打印顺序 2 4 3 1

1. 遇到setTimeout,异步宏任务将其放到宏任务列表中 命名为time1;

2. new Promise 在实例化过程中所执⾏的代码都是同步执⾏的(function中的代

码),输出2;

3. 将Promise中注册的回调函数放到微任务队列中,命名为then1;

4. 执⾏同步任务console…log('4') ,输出4,⾄此执⾏栈中的代码执⾏完毕;

5. 从微任务队列取出任务then1到主线程中,输出3,⾄此微任务队列为空;

6. 从宏任务队列中取出任务time1到主线程中,输出1,⾄此宏任务队列为空。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值