Node.JS——学习笔记
2020年02月23日11:52:01
我打算自学NodeJS-通过阅读NodeJS官网来完成。
https://nodejs.org/dist/latest-v13.x/docs/api/
https://www.liaoxuefeng.com/wiki/1022910821149312/1023025235359040
初识Node.js
Node.js® 是一个基于 Chrome V8 引擎 的 JavaScript 运行时。
安装Node.js
下载-安装
运行首个Node.js程序
- 创建
app.js
文件,代码如下
//创建 app.js文件,使用node app.js 运行
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
-
使用
node app.js
命令,运行Node程序。访问。OK。运行成功~
模块(module)
初始模块
-
创建代码,认识模块的调用
'use strict'; console.log("hello world"); var s = "Hello"; function greet(name){ console.log(s+","+name) } function greet2(){ console.log("1") } module.exports = { greet:greet, greet2:greet2 }
这里自己做了一个小实验,关于多模块的引用和单模块引用的区别。
'use strict'; //引入hello 模块 var greet = require('./hello').greet; var greet2 = require('./hello').greet2; var name = 'Michael'; greet("大娃"); greet2();
在这里我想说,万物皆是对象。
-
关于局部变量的问题,这里也解释一下。如果看了node的底层module实现源码,确很容易弄懂。
基本模块
global全局对象和process线程对象
**golbal ** 全局对象
在前面的JavaScript课程中,我们已经知道,JavaScript有且仅有一个全局对象,在浏览器中,叫
window
对象。而在Node.js环境中,也有唯一的全局对象,但不叫window
,而叫global
,这个对象的属性和方法也和浏览器环境的window
不同。
> global.console
{
log: [Function: bound consoleCall],
warn: [Function: bound consoleCall],
dir: [Function: bound consoleCall],
time: [Function: bound consoleCall],
timeEnd: [Function: bound consoleCall],
timeLog: [Function: bound consoleCall],
trace: [Function: bound consoleCall],
assert: [Function: bound consoleCall],
clear: [Function: bound consoleCall],
count: [Function: bound consoleCall],
countReset: [Function: bound consoleCall],
group: [Function: bound consoleCall],
groupEnd: [Function: bound consoleCall],
table: [Function: bound consoleCall],
debug: [Function: bound consoleCall],
info: [Function: bound consoleCall],
dirxml: [Function: bound consoleCall],
error: [Function: bound consoleCall],
groupCollapsed: [Function: bound consoleCall],
Console: [Function: Console],
profile: [Function: profile],
profileEnd: [Function: profileEnd],
timeStamp: [Function: timeStamp],
context: [Function: context],
...//大娃手动省略,太多了
}
process 线程对象
process
也是Node.js提供的一个对象,它代表当前Node.js进程。
> process
process {
version: 'v13.9.0',
versions: {
node: '13.9.0',
v8: '7.9.317.25-node.28',
uv: '1.34.2',
zlib: '1.2.11',
brotli: '1.0.7',
ares: '1.15.0',
modules: '79',
nghttp2: '1.40.0',
napi: '5',
llhttp: '2.0.4',
openssl: '1.1.1d',
cldr: '36.0',
icu: '65.1',
tz: '2019c',
unicode: '12.1'
},
arch: 'x64',
platform: 'darwin',
release: {
name: 'node',
sourceUrl: 'https://nodejs.org/download/release/v13.9.0/node-v13.9.0.tar.gz',
headersUrl: 'https://nodejs.org/download/release/v13.9.0/node-v13.9.0-headers.tar.gz'
},
_rawDebug: [Function: _rawDebug],
moduleLoadList: [
...//大娃手动省略。太多了
],
binding: [Function: binding],
_linkedBinding: [Function: _linkedBinding],
_events: [Object: null prototype] {
newListener: [ [Function: startListeningIfSignal], [Function (anonymous)] ],
removeListener: [ [Function: stopListeningIfSignal], [Function (anonymous)] ],
warning: [Function: onWarning],
SIGWINCH: [Function (anonymous)]
},
_eventsCount: 4,
_maxListeners: undefined,
domain: [Getter/Setter],
_exiting: false,
config: {
target_defaults: {
cflags: [],
default_configuration: 'Release',
defines: [],
include_dirs: [],
libraries: []
},
variables: {...}//手动省略
},
...//大娃手动省略,内容太多了
env: {
...//大娃手动省略,内容太多了。
},
title: 'node',
argv: [ '/usr/local/bin/node' ],
execArgv: [],
pid: 10379,
ppid: 6491,
execPath: '/usr/local/bin/node',
debugPort: 9229,
argv0: 'node',
_preload_modules: [],
[Symbol(kCapture)]: false
}
//大娃批注:**一个process,就能查询出当前线程基本上所有的Info**
fs(文件系统模块)
Node.js内置的
fs
模块就是文件系统模块,负责读写文件。和所有其它JavaScript模块不同的是,
fs
模块同时提供了异步和同步的方法。
-
异步读文件
'use strict'; var fs = require('fs'); fs.readFile('sample.txt', 'utf-8', function (err, data) { if (err) { console.log(err); } else { console.log(data); } }); //请注意,sample.txt文件必须在当前目录下,且文件编码为utf-8。
-
同步读文件
除了标准的异步读取模式外,
fs
也提供相应的同步读取函数。同步读取的函数和异步函数相比,多了一个Sync
后缀,并且不接收回调函数,函数直接返回结果。'use strict'; var fs = require('fs'); var data = fs.readFileSync('sample.txt', 'utf-8'); console.log(data); // 可见,原异步调用的回调函数的data被函数直接返回,函数名需要改为readFileSync,其它参数不变。
-
异步写文件
将数据写入文件是通过
fs.writeFile()
实现的:'use strict'; var fs = require('fs'); var data = 'Hello, Node.js'; fs.writeFile('output.txt', data, function (err) { if (err) { console.log(err); } else { console.log('ok.'); } }); //writeFile()的参数依次为文件名、数据和回调函数。如果传入的数据是String,默认按UTF-8编码写入文本文件,如果传入的参数是Buffer,则写入的是二进制文件。回调函数由于只关心成功与否,因此只需要一个err参数。
-
同步写文件
和
readFile()
类似,writeFile()
也有一个同步方法,叫writeFileSync()
:'use strict'; var fs = require('fs'); var data = 'Hello, Node.js'; fs.writeFileSync('output.txt', data);
-
stat()方法:获取文件或者目录的信息
如果我们要获取文件大小,创建时间等信息,可以使用
fs.stat()
,它返回一个Stat
对象,能告诉我们文件或目录的详细信息:'use strict'; var fs = require('fs'); fs.stat('sample.txt', function (err, stat) { if (err) { console.log(err); } else { // 是否是文件: console.log('isFile: ' + stat.isFile()); // 是否是目录: console.log('isDirectory: ' + stat.isDirectory()); if (stat.isFile()) { // 文件大小: console.log('size: ' + stat.size); // 创建时间, Date对象: console.log('birth time: ' + stat.birthtime); // 修改时间, Date对象: console.log('modified time: ' + stat.mtime); } } });
-
异步还是同步?
在
fs
模块中,提供同步方法是为了方便使用。那我们到底是应该用异步方法还是同步方法呢?由于Node环境执行的JavaScript代码是服务器端代码,所以,绝大部分需要在服务器运行期反复执行业务逻辑的代码,必须使用异步代码,否则,同步代码在执行时期,服务器将停止响应,因为JavaScript只有一个执行线程。
服务器启动时如果需要读取配置文件,或者结束时需要写入到状态文件时,可以使用同步代码,因为这些代码只在启动和结束时执行一次,不影响服务器正常运行时的异步执行。
-
自己写的demo
'use strict'; var fs = require('fs'); // 异步读取文件操作 fs.readFile('test.js','utf-8',function(err,data){ if(err){ console.log('error'); }else{ console.log(data); } }) var content = "hello world"; // 异步写文件操作 fs.writeFile('write.js',content,function(err){ if (err) { console.log(err); } else { console.log('ok'); } }) //stat状态查询 fs.stat('write.js',function (err,stat) { if (err) { console.log(err); } else { console.log(stat.size); } })
stream
stream
是Node.js提供的又一个仅在服务区端可用的模块,目的是支持“流”这种数据结构。
大娃评价:和java8提供的stream流结构一样。
-
读流 ()
'use strict'; var fs = require('fs'); // 打开一个流: var rs = fs.createReadStream('sample.txt', 'utf-8'); rs.on('data', function (chunk) { console.log('DATA:') console.log(chunk); }); rs.on('end', function () { console.log('END'); }); rs.on('error', function (err) { console.log('ERROR: ' + err); });
-
写流 ()
'use strict'; var fs = require('fs'); var ws1 = fs.createWriteStream('output1.txt', 'utf-8'); ws1.write('使用Stream写入文本数据... '); ws1.write('END.'); ws1.end(); var ws2 = fs.createWriteStream('output2.txt'); ws2.write(new Buffer('使用Stream写入二进制数据... ', 'utf-8')); ws2.write(new Buffer('END.', 'utf-8')); ws2.end();
-
pipe ()
'use strict'; var fs = require('fs'); var rs = fs.createReadStream('sample.txt'); var ws = fs.createWriteStream('copied.txt'); rs.pipe(ws);
HTTP
要开发HTTP服务器程序,从头处理TCP连接,解析HTTP是不现实的。这些工作实际上已经由Node.js自带的
http
模块完成了。应用程序并不直接和HTTP协议打交道,而是操作http
模块提供的request
和response
对象。
request
对象封装了HTTP请求,我们调用request
对象的属性和方法就可以拿到所有HTTP请求的信息;
response
对象封装了HTTP响应,我们操作response
对象的方法,就可以把HTTP响应返回给浏览器。
-
用Node.js实现一个HTTP服务器程序
'use strict'; //导入HTTP模块 var http = require("http"); //创建服务器对象 var server = http.createServer(function(request,response) { console.log(request.url); response.writeHead(200,{'Content-Type':'text/html'}); response.end('<h1>hello world</h1>'); }); server.listen(8080); console.log("Server is running at 8080 port");
URL
解析URL需要用到Node.js提供的
url
模块,它使用起来非常简单,通过parse()
将一个字符串解析为一个Url
对象.
'use strict';
var url = require('url');
console.log(url.parse('http://user:pass@host.com:8080/path/to/file?query=string#hash'));
//解析结果如下
Url {
protocol: 'http:',
slashes: true,
auth: 'user:pass',
host: 'host.com:8080',
port: '8080',
hostname: 'host.com',
hash: '#hash',
search: '?query=string',
query: 'query=string',
pathname: '/path/to/file',
path: '/path/to/file?query=string',
href: 'http://user:pass@host.com:8080/path/to/file?query=string#hash' }
PATH
处理本地文件目录需要使用Node.js提供的
path
模块,它可以方便地构造目录
通过HTTP,URL,FS,PATH
用代码去认识:构造了一个文件系统
"use strict";
var fs = require("fs"),
url = require("url"),
path = require("path"),
http = require("http");
//从命令行参数获取当前线程的root目录,默认目录是当前目录
var root = path.resolve(process.argv[2] || ".");
console.log("static root dir:" + root);
//创建service
var server = http.createServer(function(request, response) {
//获取URL的path
var pathname = url.parse(request.url).pathname;
//获取对应的本地文件路径
var filepath = path.join(root, pathname);
//获取文件状态
fs.stat(filepath, function(err, stats) {
if (!err && stats.isFile()) {
// 没错
console.log("200 " + request.url);
response.writeHead(200);
fs.createReadStream(filepath).pipe(response);
} else {
// 出错
console.log("404 " + request.url);
response.writeHead(404);
response.end("404 Not Fount");
}
});
});
server.listen(8080);
console.log("server is running at http : 8080");
浏览器访问到本地文件:
控制台输出:
static root dir:/Users/shangyifeng/Desktop/js
filePath.js:10
server is running at http : 8080
filePath.js:35
404 /
filePath.js:27
404 /favicon.ico
filePath.js:27
200 /app.js
filePath.js:22
404 /filePa
filePath.js:27
200 /filePath.js
filePath.js:22
200 /app.js
crypto
crypto模块的目的是为了提供通用的加密和哈希算法。用纯JavaScript代码实现这些功能不是不可能,但速度会非常慢。Nodejs用C/C++实现这些算法后,通过cypto这个模块暴露为JavaScript接口,这样用起来方便,运行速度也快。
MD5 && SHA1
const crypto = require('crypto');
const hash = crypto.createHash('md5');
// 可任意多次调用update():
hash.update('Hello, world!');
hash.update('Hello, nodejs!');
console.log(hash.digest('hex')); // 7e1977739c748beac0c0fd14fd26a544
官网介绍了很多种语法
https://nodejs.org/dist/latest-v13.x/docs/api/crypto.html
over,暂时就这样
其他API
官网内容最详细,此行的目的仅是为了简单的了解nodejs,方便自己学习Vue这些前端框架。
https://nodejs.org/dist/latest-v13.x/docs/api/
详情内容,以后用到,再查询官网。
2020年02月25日07:40:07
规划了一下自己的学习路线,觉得node暂时认知到这里就这样就行了。