JavaScript on the Serverhtml
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.node
JavaScript是前端开发的惟一标准。git
2000年后开始的浏览器平台大战,致使了node的诞生。es6
在2009年,Ryan(人)正式推出了基于JavaScript语言和V8引擎的开源Web服务器项目,命名为Node.js。github
选择js,是由于它是单线程,只能使用异步IO。web
Node第一次把JavaScript带入到后端服务器开发,加上世界上已经有无数的JavaScript开发人员,因此Node一会儿就火了起来。算法
最大的优点是借助JavaScript天生的事件驱动机制加V8高性能引擎,使编写高性能Web服务垂手可得。chrome
其次,JavaScript语言自己是完善的函数式语言,在前端开发时,开发人员每每写得比较随意,让人感受JavaScript就是个“玩具语言”。可是,在Node环境下,经过模块化的JavaScript代码,加上函数式编程,而且无需考虑浏览器兼容性问题,直接使用最新的ECMAScript 6标准,能够彻底知足工程上的需求。express
(见以前的博客)
安装成功后使用node -v和npm -v查看版本。
在终端输入node, 进入Node.js的交互环境。能够输入任何js语句。
退出.exit,或者按两次ctrl+c.
选择偶数的版本,node核心团队维护这类版本的时间达数年之久。具体须要看官网/git(👆的链接)
奇数版本,属于实验性版本,维护时间1年左右。
维护指:security vulnerability, patches(补丁)
再看视频(2016版本使用express+ MongoDB)
学习Koa(文章)(廖雪峰上也有)
视频(YoutTube):https://www.youtube.com/watch?v=PT_-u2fFTaI&list=PLguYmmjtxbWHY2vCHIkugUpNdzE3QNOvf&index=4&t=0s
//使用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
输入的js代码,每行结果自动打印出来。
这相似进入chrome浏览器的控制台,其实至关于启动了Node解释器,每输入一行就执行一行。
而直接使用node <file-name>, 至关于一次性把文件的源代码给Node解释器执行了。
在编写JavaScript代码的时候,能够一边在文本编辑器里写代码,一边开一个Node交互式命令窗口,
在写代码的过程当中,把部分代码粘到命令行去验证,效率会提高。
支持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.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); });
有些时候,程序自己须要判断本身究竟是在什么环境下执行的,经常使用的方式就是根据浏览器和Node环境提供的全局变量名称来判断:
if (typeof(window) === undefined) { //表明时node.js环境 } else { //浏览器环境 }
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
捕获该错误
fs.writeFile(fileName, data, callback(err))
一样,有一个同步方法: writeFileSync(fileName, data)
使用fs.stat(fileName, callback(err, stat))来返回一个Stat对象,它包含文件或目录的详细信息。
也有同步函数fs.statSync()
由于Node环境执行的是服务器端代码,绝大部分须要在服务器上反复执行逻业务辑的代码,必须使用异步代码。否则,同步代码在执行时期,服务器将中止响应,由于JavaScript只有一个执行线程。
服务器启动时若是须要读取配置文件,或者结束时须要写入到状态文件时,可使用同步代码,由于这些代码只在启动和结束时执行一次,不影响服务器正常运行时的异步执行。
一个stream是一个抽象接口,用于Node.js内的streaming data。
Stream module提供了基本的API,能够创建对象执行stream interface.
在Node.js, 流是一个对象。
Node.js提供了许多stream objects,例如,一个发向一个HTTP server的请求,process.stdout。
咱们只须要响应流的事件便可:
例子,读取流:
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。
4种基本类型:
例子,以流的形式写入文件,只要不断调用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
。
就像能够把两个水管串成一个更长的水管同样,两个流也能够串起来。一个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模块会处理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模块的目的是为了提供通用的加密和哈希算法。
包括:a set of wrappers for OpenSSL's hash, HMAC, cipher, decipher, sign, and verify functions.
用纯JavaScript代码实现这些功能不是不可能,但速度会很是慢。
Nodejs用C/C++实现这些算法后,经过cypto这个模块暴露为JavaScript接口,这样用起来方便,运行速度也快。
MD5是一种hash算法,用于给任意数据一个签名。这个签名用一个16进制的string表示。
crypto模块封装了hash类。
有2种使用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
还可使用更安全的sha256
和sha512
。
例子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();