Node.js 知识(教程)

JavaScript on the Server

JavaScript was originally built for web browsers, but with Node.js we can use it on the server.

We can perform server-related tasks like file system access.

 

历史:

JavaScript是前端开发的唯一标准。

2000年后开始的浏览器平台大战,导致了node的诞生。

在2009年,Ryan(人)正式推出了基于JavaScript语言和V8引擎的开源Web服务器项目,命名为Node.js。

选择js,是因为它是单线程,只能使用异步IO。

Node第一次把JavaScript带入到后端服务器开发,加上世界上已经有无数的JavaScript开发人员,所以Node一下子就火了起来。

 

在Node上运行的JavaScript相比其他后端开发语言有何优势?

最大的优势是借助JavaScript天生的事件驱动机制加V8高性能引擎,使编写高性能Web服务轻而易举。

其次,JavaScript语言本身是完善的函数式语言,在前端开发时,开发人员往往写得比较随意,让人感觉JavaScript就是个“玩具语言”。但是,在Node环境下,通过模块化的JavaScript代码,加上函数式编程,并且无需考虑浏览器兼容性问题,直接使用最新的ECMAScript 6标准,可以完全满足工程上的需求。

 


 

 

安装Node.js和npm

(见之前的博客)

安装成功后使用node -v和npm -v查看版本。

在终端输入node, 进入Node.js的交互环境。可以输入任何js语句。

退出.exit,或者按两次ctrl+c.

 

关于node的版本选择。

选择偶数的版本,node核心团队维护这类版本的时间达数年之久。具体需要看官网/git(?的连接)

奇数版本,属于实验性版本,维护时间1年左右。

维护指:security vulnerability, patches(补丁)

 

 


 

先看廖雪峰

再看视频(2016版本使用express+ MongoDB)

学习Koa(文章)(廖雪峰上也有)

 

大神的node书,免费

视频(YoutTube):https://www.youtube.com/watch?v=PT_-u2fFTaI&list=PLguYmmjtxbWHY2vCHIkugUpNdzE3QNOvf&index=4&t=0s

 

 


 

新建一个node文件

在命令行:
//使用mac自带的vim编辑器,也可以使用atom等
vi hello.js

//然后输入js代码,保存
//在所存文件的文件夹下,输入
node hello.js
//在terminal上, 显示consol.log()打印的代码。

 

hello.js

'use strict';

console.log('Hello, world.');

//另外,如果不写‘use strict’,可以在terminal上使用:
//node --use_strict hello.js

 

在node交互环境下:

输入的js代码,每行结果自动打印出来。

这类似进入chrome浏览器的控制台,其实相当于启动了Node解释器,每输入一行就执行一行。

而直接使用node <file-name>, 相当于一次性把文件的源代码给Node解释器执行了。

 

使用27存大显示器的好处:

在编写JavaScript代码的时候,可以一边在文本编辑器里写代码,一边开一个Node交互式命令窗口,

在写代码的过程中,把部分代码粘到命令行去验证,效率会提升。

 

文件作为模块的import和export:

支持es6的语法。如template string。`...``

在node环境下,不支持使用import,export。需要使用module是一个自动生成的对象,用于输出。

//其基本结构;具体结构进入node,然后输入global.module。
var module = {
  id: 'xxx',
  exports: {}
}

 

module.exportes = variable

var var1 = require('相对路径')


⚠️require()方法,是node.js的modules功能,在chrome browser 控制台上会报告❌ReferenceError,不支持。 

具体见之前的博客:https://www.cnblogs.com/chentianwei/p/10197813.html


 

Node的基本模块(廖雪峰文章摘录)

因为Node.js是运行在服务区端的JavaScript环境,服务器程序和浏览器程序相比,最大的特点是没有浏览器的安全限制了,而且,服务器程序必须能接收网络请求,读写文件,处理二进制内容,所以,Node.js内置的常用模块就是为了实现基本的服务器功能。这些模块在浏览器环境中是无法被执行的,因为它们的底层代码是用C/C++在Node.js运行环境中实现的。

 

global

进入Node.js交互环境,输入global.console可以看到Console对象的属性

 

process

也是一个对象,代表当前的进程, 输入global.process,可以看到相关信息。

> process === global.process
true

 相关命令

> process.version;
'v5.2.0'
> process.platform;
'darwin'
> process.arch;
'x64'
> process.cwd(); //返回当前工作目录
'/Users/michael'
> process.chdir('/private/tmp'); // 切换当前工作目录
undefined
> process.cwd();
'/private/tmp'
> process.exit() //退出进程

 

JavaScript程序是由事件驱动执行的单线程模型,Node.js也不例外。

Node.js不断执行响应事件的JavaScript函数,直到没有任何响应事件的函数可以执行时,Node.js就退出了。

// test.js

// process.nextTick()将在下一轮事件循环中调用:
process.nextTick(function () {
    console.log('nextTick callback!');
});
console.log('nextTick was set!');

结果输出是

nextTick was set!
nextTick callback!

process.nextTick()函数不是马上执行,而是等到下一次事件循环。

 

Node.js进程本身的事件就是由process对象来处理的。

如果响应exit事件,就可以在程序退出时执行某个回调函数:

// 程序即将退出时的回调函数:
process.on('exit', function (code) {
    console.log('about to exit with code: ' + code);
});

 

判断JavaScript的执行环境

有些时候,程序本身需要判断自己到底是在什么环境下执行的,常用的方式就是根据浏览器和Node环境提供的全局变量名称来判断:

if (typeof(window) === undefined) {
  //代表时node.js环境
} else {
  //浏览器环境
}

 

fs  -- file system模块

const fs = require('fs');

 

用于读写文件系统的文件。它提供了异步方法。

 

异步读取文件:

var fs = require('fs')

fs.readFile('sample.txt', 'utf-8', (err, data) => {
    if (err) {
        console.log(err);
    } else {
        console.log(data);
    }
})

 

'sample.txt'是当前路径内的文件的名字,'utf-8'是文件编码。

传入的回调函数接收2个参数err, data,这是标准的Node.js回调函数,第一个参数处理❌,第二个参数处理正确的结果。

例子:

$mkdir htt2
$cd htt2
$npm init -y
$touch fs.js
$vi sample.txt //编写一些语句,然后:wq

 

'use strict';

var fs = require('fs');

fs.readFile('sample.txt', 'utf-8', function (err, data) {
    if (err) {
        console.log(err);
    } else {
        console.log(data);
        console.log(data.length + ' bytes');
    }
});

 

$node fs 

 

显示:

hello everybody!

17 bytes

 

⚠️,如果不使用'utf-u', terminal上显示一个Buffer对象。
<Buffer 68 65 6c 6c 6f 20 65 76 65 72 79 62 6f 64 79 21 0a>

Buffer对象可以和String对象做转换。

//fs.js
//在回调函数内加上
        var text = data.toString('utf-8')
        console.log(text)

 

相反使用: Buffer.from(text, 'utf-8')

//node环境下
> var text  = "hello everybody!"> Buffer.from(text, 'utf-8')
<Buffer 68 65 6c 6c 6f 20 65 76 65 72 79 62 6f 64 79 21>

 

同步读取文件

fs.readFileSync()

'use strict';

var fs = require('fs');

var data = fs.readFileSync('sample.txt', 'utf-8');
console.log(data);

如果同步读取文件发生错误,则需要用try...catch捕获该错误

 

write 文件

fs.writeFile(fileName, data, callback(err))

  • 文件名
  • 数据如果是String,则默认用utf-8编码写入文本文件,如果传入的是Buffer则写入的是二进制的文件
  • 回调函数只关心是否成功,所以只有err一个参数。

同样,有一个同步方法: writeFileSync(fileName, data)

 

fs.stat()

使用fs.stat(fileName, callback(err, stat))来返回一个Stat对象,它包含文件或目录的详细信息。

也有同步函数fs.statSync()

 

异步函数为主

因为Node环境执行的是服务器端代码,绝大部分需要在服务器上反复执行逻业务辑的代码,必须使用异步代码。否则,同步代码在执行时期,服务器将停止响应,因为JavaScript只有一个执行线程。

 

服务器启动时如果需要读取配置文件,或者结束时需要写入到状态文件时,可以使用同步代码,因为这些代码只在启动和结束时执行一次,不影响服务器正常运行时的异步执行。


 

 

Stream

一个stream是一个抽象接口,用于Node.js内的streaming data。

Stream module提供了基本的API,可以建立对象执行stream interface.

 

在Node.js, 流是一个对象。

Node.js提供了许多stream objects,例如,一个发向一个HTTP server的请求,process.stdout。

我们只需要响应流的事件即可:

  • data事件,表示流的数据已经可以读取了
  • end事件,表示这个流已经到末尾了
  • 没有数据可以读取,error事件表示出错了

例子,读取流:

var fs = require('fs')
//打开一个只读的流
var rs = fs.createReadStream('sample.txt', 'utf-8')

rs.on('data', function(chunk) {
  console.log(`Data: ${chunk}`)
})

rs.on('end', () => {
  console.log('End.')
})

rs.on('error', (err) => {
  console.log(`"Error: ${err}`)
})

 

Streams是可读写的。所有的流都是EventEmitter类的实例。因此可以使用它的实例方法了。这些实例方法大多是用于监听事件events及相关操作。

比如上例子的on(eventName, listener),当data事件,end事件完成时,同步执行附加的函数。

 

其实所有的可以emit事件的objects都是EventEmitter类的实例。这些objects使用on()方法,让一个或多个函数附加到由这个object发射的event上。

当EventEmitter对象发射emit一个事件时,所有的附加到这个事件的函数被同步地调用。

 

使用下面的语法,取stream module:

const stream = require('stream');

 

stream模块对正在创建新的类型的流实例的开发者来说,是非常有用的。

Developers who are primarily consuming stream objects will rarely need to use the stream module directly.

 那些主要地消耗流对象的开发者则很少需要直接地使用stream module。

 

Types of Streams

4种基本类型:

  • Writable: 数据可以被写入。 fs.createWriteStream()
  • Readable: 数据可以被读取。fs.createReadStream()
  • Duplex:  数据可读写的。 net.Socket
  • Transform:  这种流是Duplex流,它的输出某种程度上和输入相关。例如: crypto streams

 

例子,以流的形式写入文件,只要不断调用write()方法,最后end()方法结束。

var ws1 = fs.createWriteStream('sample.txt', 'utf-8')
ws1.write('使用Stream写入文本数据...\n')
ws1.write('end!')
ws1.end();

var ws2 = fs.createWriteStream('output2.txt');
ws2.write(Buffer.from('使用Stream写入二进制数据...\n'));
ws2.write(Buffer.from('END.'));
ws2.end();

 

 

所有可以读取数据的流都继承自类stream.Readable

所有可以写入的流都继承自类stream.Writable

 

Pipe

就像可以把两个水管串成一个更长的水管一样,两个流也可以串起来。一个Readable流和一个Writable流串起来后,所有的数据自动从Readable流进入Writable流,这种操作叫pipe

 

Readable.pipe(目的地,选项)方法,就可以做这件事情。

让我们用pipe()把一个文件流和另一个文件流串起来,这样源文件的所有数据就自动写入到目标文件里了,所以,这实际上是一个复制文件的程序:

var fs = require('fs');

var rs = fs.createReadStream('sample.txt');
var ws = fs.createWriteStream('copied.txt');

rs.pipe(ws);

同时也有事件pipe, unpipe

Readable.pipe的选项end默认是true, 表示end事件触发后,会自动关闭Writable流。如果不像自动关闭则:

readable.pipe(writable, { end: false });

 


 

 

http模块摘要

http模块会处理Tcp连接,解析HTTP。

app不直接和HTTP协议打交道,而是使用http模块提供的request和response对象

var http = require('http')

var server = http.createServer((req, res) => {
  console.log(`${req.method}:${req.url}`)
  res.writeHead(200, { 'Content-Type': 'text/html'})
  res.end('<h1>hello</h1>')
})

server.listen(3000)

 

request对象应该使用了IncomingMessage类的实例方法method, url

response对象,是类http.ServerResponse的实例,上面的代码使用了writeHead方法


 

crypto模块

crypto模块的目的是为了提供通用的加密和哈希算法。

包括:a set of wrappers for OpenSSL's hash, HMAC, cipher, decipher, sign, and verify functions.

用纯JavaScript代码实现这些功能不是不可能,但速度会非常慢。

Nodejs用C/C++实现这些算法后,通过cypto这个模块暴露为JavaScript接口,这样用起来方便,运行速度也快。

 

MD5 and SHA1

MD5是一种hash算法,用于给任意数据一个签名。这个签名用一个16进制的string表示。

crypto模块封装了hash类。

有2种使用Hash类的方法:

  • 作为一个stream, 可以读写,写入数据来产生一个可计算的hash digest。
  • 使用hash.update(), hash.digest()方法产生一个可计算的hash。

例子1:

//在terminal进入node环境
const crypto = require('crypto')
const hash = crypto.createHash('sha256')    //产生一个Hash实例
hash.update('some date to hash')
//返回
Hash {
  _options: undefined,
  writable: true,
  readable: true,
  [Symbol(kHandle)]: {},
  [Symbol(kState)]: { [Symbol(kFinalized)]: false } } 

hash.digest('hex')  //hex是16进制的意思。
// Prints:
//   6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50

 

还可以使用更安全的sha256sha512

 

例子2

hash对象是一个stream。可读写的,当hash被写入数据后,因为data是可以被读的,readable事件会emit.

const crypto = require('crypto');
const fs = require('fs');
const hash = crypto.createHash('sha256');

hash.on('readable', () => {
  // Only one element is going to be produced by the
  // hash stream.
  const data = hash.read();
  if (data) {
    console.log(data.toString('hex'));
    // Prints:
    // 6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50
  }
});

hash.write('some data to hash');
hash.end();

 

 

 

其他算法见这篇教程

 

转载于:https://www.cnblogs.com/chentianwei/p/10238234.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值