NodeJS是开发服务器后台的东西,和PHP、JavaEE、python相似,和传统的浏览器的关注DOM的JS彻底不一样,将JavaScript触角伸到了服务器端。内核是Chrome浏览器的V8引擎,解析JavaScript的效率是很是快的。javascript
创始人。php
在不升级服务器配置的状况下,如何用软件手段来提高服务器性能:Ryan Dahl大体的感受到了解决问题的关键是要经过事件驱动和异步I/O来达成目的。html
传统的服务器模型:当咱们作I/O操做的时候(I表示读,O表示写),CPU被磁盘操做阻塞了,此时咱们称这叫作“同步I/O(synchronous I/O),阻塞I/O(blocking I/O)”。前端
CPU会常常对磁盘驱动发出I/O命令java
此时磁盘特别忙,CPU就歇着了。形成了资源浪费。上图这种模式叫作“同步I/O”。node
同步(synchronous):当系统碰见了一个须要耗费大量时间的事情的时候,选择死等。
异步(Asynchronous):当系统碰见了一个须要耗费大量时间的事情的时候,不死等,先作后面的事情,耗时事情作完以后,执行回调函数。
用PHP作一个例子:下面程序中红色部分是I/O操做,此时CPU被阻塞,此时为何不限作蓝色计算部分?等红色部分作完了用“回调函数”来显示文件内容多好。python
<?php //读取文件 $myfile = fopen("txt.txt", "r"); //打印文件内存 echo fread($myfile, filesize("txt.txt")); for($i = 2; $i < 100; $i++){ $count = 0; for($j = 1; $j <= $i; $j++){ if($i % $j == 0){ $count++; } } if($count == 2){ echo $i."<br/>"; } } fclose($myfile); ?>
V8引擎来了。V8知足他关于高性能Web服务器的想象:webpack
● 没有历史包袱,没有同步I/O。不会出现一个同步I/O致使事件循环性能急剧下降的状况。web
● V8性能足够好,远远比Python、Ruby等其余脚本语言的引擎快。chrome
● JavaScript语言的闭包特性很是方便,比C中的回调函数好用。
创始人Ryan Dahl想到了用V8引擎内核,用JS当作语言去开发服务端程序。
下面是Nodejs的画风,Nodejs不是语言,语言是JavaScript,Nodejs是一个平台,让咱们的JS能够运行在服务端的平台。
var fs = require("fs"); fs.readFile("./txt.txt" ,function(err, data){ console.log(data.toString()); }) for(var i = 2; i < 100; i++){ count = 0; for(var j = 1; j <= i;j++){ if(i % j == 0){ count++; } } if(count == 2){ console.log(i) } }
红色的I/O操做没有将蓝色计算操做阻塞,称为“Non-Blocking I/O”非阻塞I/O。紫色语句是回调函数。
NodeJS是一个JS运行环境,它构建在chrome的V8引擎上。使用了事件驱动、非阻塞I/O模型,使它轻量而且方便。NodeJS有一个全球最大的包生态系统npm。
Node.js使JavaScript的触角伸到了服务器开发中,在Node的世界中,咱们关心的再也不是用JS操做网页上的DOM、制做交互动画、表单验证……而是服务器端的事情:HTTP请求的处理、GET请求和POST请求、数据库增删改查、cookie和session等等。
Node.js的特色:单线程、非阻塞异步I/O、事件驱动。
Nodejs是JS的运行环境,它构建在Chrome的V8引擎上。
Nodejs是一个小极客,追求极致的服务器性能,剑走偏锋的产物。
与其不少服务员闲着,还不如一个服务员100%的工做。
NodeJS和Java虚拟机同样,是跨平台的,也就是说只要写一份代码,能够运行在任何平台上。
去NodeJS官网下载:
|
安装的欢迎界面 |
|
赞成协议 |
|
安装路径全程不能有中文。 事实上不少软件公司已经去中文化,文档都是英语的文件名,文件夹都是英语的。 |
|
这个界面不须要改变任何的配置,可是要知道:这里安装了4个东西。
|
|
点击下一步就开始安装了 |
|
系统的防火墙,选择是 |
|
nodejs已经被成功的安装。 |
安装完毕以后,按windows键加R键(run),输入cmd(表示commond命令)按回车:
这是系统的密令提示符,能够输入相似DOS的命令。可是如今要输入
node -v
追求如下真理,安装过程,到底发生了什么?发现了一个Nodejs程序:
咱们发现系统的环境变量中,已经添加了这个路径:
系统的环境变量能够保证咱们的node在任意CMD盘符下能够被运行。
nodejs在windows中是一个exe程序。
在c盘建立一个nodejs_study文件,而后写01.js文件
将文件拖拽到浏览器中不能执行的。
由于js的执行须要宿主环境(runtime),目前咱们只知道一个环境:浏览器+HTML环境。
想要运行01.js程序:
<html> <head> <meta charset="UTF-8" /> <title>Document</title> </head> <body> </body> <script type="text/javascript" src="01.js"></script> </html>
浏览器会渲染html就能执行js。
NodeJS是一个全新的JS宿主环境runtime。也就是说能够用node运行js程序,而不须要html和浏览器。
打开CMD,首先注意光标所在盘符位置:
01.js文件不在C:\Users\admin>中,而是在C:\nodejs_study,因此要用cd命令来切换光标所在盘符位置:
当用cd切换到01.js所在目录时,此时能够用node命令执行js文件:
也就是说,运行js文件的时候:
① 要保证光标所在位置正确
② 运行谁,就node谁。
为了快速打开正确光标所在位置,此时有奇淫技巧:
要求你们,在运行node程序的时候,必须进入准确的盘符,不能使用绝对路径:
最快的运行node程序的方法就是使用visual studio code,或者webstrom。直接按F5,IDE(编程工具)内置的控制台会输出结果。
CMD的命令:
cls
清屏。
cd ..
回退到上一级文件夹
cd 文件夹名字
进入这个文件夹
dir
列出当前目录中全部的文件
↑上箭头
重复上一条指令。
NodeJS没有本身的语法,JS能写什么,node就能运行什么
可是要注意,仅限于JS语言核心部分。DOM、BOM不能用,node没有浏览器的那些东西。
document.getElementById("box"); window alert()
可是能够用定时器
setInterval(function(){ console.log(Math.random()); },100)
按ctrl+c能够打断Nodejs程序的执行。
Nodejs中提供了不少内置模块,帮助咱们开发,能够提供浏览器所不具有的功能,模块是内置的,不须要额外安装。从fs内置模块学起,fs是file system文件系统的意思,提供了对文件的全部操做
// require表示获得,引入fs内置模块,file system文件系统模块 var fs = require("fs"); //fs模块有个方法叫readFile,能够异步读文件内容 //这个函数是异步函数,也就是说读取文件不会阻塞CPU执行,因此读取到的内容经过回调函数返回 //err参数:错误信息,没有错误将返回null //data参数:返回文件的内容 fs.readFile("./test1.txt",function(err,data){ if(err){ console.log("文件读取错误!"); return; } //读取的是信息流,是Buffer是缓冲的二进制,用toString()转为字符串 console.log(data.toString()); });
利用fs.readFile()这个API来读取文件,而且是异步读取文件,这里注意两个事情:
1) 第一个参数是路径,必须以"./"开头,表示从相对于当前的cmd盘符位置去读取文件。
2) 第二个参数是回调函数,注意回调函数中提供了两个参数,分别是err和data。注意,nodejs中的全部回调函数的第一个参数都是err对象,表示错误。若是没有错误,这个对象是null。
要会看API:https://nodejs.org/dist/latest-v6.x/docs/api/
var fs = require("fs"); fs.readFile("./test1.txt",function(err,data){ console.log(data.toString()); }); fs.readFile("./test2.txt",function(err,data){ console.log(data.toString()); }); fs.readFile("./test3.txt",function(err,data){ console.log(data.toString()); });
在Nodejs中要适应回调套回调函数的写法:
var fs = require("fs"); fs.readFile("./test1.txt",function(err,data){ console.log(data.toString()); fs.readFile("./test2.txt",function(err,data){ console.log(data.toString()); fs.readFile("./test3.txt",function(err,data){ console.log(data.toString()); }); }); });
用http模块,Nodejs能够开发服务器。建立服务器的API要本身背诵记忆一下,不过,后面讲解Express,极大简化服务器的建立:
var http = require('http'); //读取内置http模块,这个模块提供了http服务 //建立一个服务器,是异步函数,事实上node中基本全部函数都是异步的 var server = http.createServer(function(req,res){ //req表示request用户的请求 //res表示response服务器的响应 //设置响应报文头,让类型变为html而且是utf8编码 res.setHeader("Content-type", "text/html;charset=UTF8"); //页面上输出内容,输出内容用write,end表示结束! res.end("<h1>你好,我是nodejs开发的服务器!</h1>"); }); //监听3000端口,默认是80端口,但80被Apache占用了,因此改用3000 server.listen(3000,function(err){ if(err){ console.log("服务器开启失败!"); return; } console.log("服务器开启成功,在3000端口,快打开浏览器看看吧!"); });
此时CMD会被挂起,按ctrl+c打断(打断以后,服务器也打不开了)
咱们来验证程序确实在服务器上运行的:
var http = require('http'); var server = http.createServer(function(req,res){ res.setHeader("Content-type", "text/html;charset=UTF8"); res.end("<h1>你好,我是nodejs开发的服务器!已经诞生了"+ (3 + 3) +"年了</h1>"); }); server.listen(3000);
在浏览器中,看不到后端node的源代码:
缘由是Nodejs执行在服务器端,语句在服务器被执行、编译,此时发给浏览器的就是执行以后、编译后的纯文本了,不含有计算的。
两个问题:
一、我用Nodejs搭建的服务器,访问者也必须安装nodejs吗。
不须要的,由于nodejs是服务器程序,生成的内容仅须要浏览器就能访问
二、咱们用高级ES6语法书写Nodejs程序,必须用高级浏览器访问吗。
不须要的,由于Nodejs程序不在浏览器执行。
req表示request用户的请求,访问者的全部必要信息在req中存储,好比
req.url
表示访问路径
req.connection.remoteAddress
表示访问者的ip地址
res表示response服务器的响应,服务器应该给与的反馈。 res.setHeader("Content-type", "text/html;charset=UTF8");
设置HTTP下行报文体
l res.end() 、res.write()负责写下行报文体(就是网页)。
res.end()结束响应,告诉客户端全部消息已经发送完毕,当全部要返回的内容发送完毕时,该函数必须被调用一次,若是不调用该函数,客户端将永远处于等待状态。
var http = require('http'); var server = http.createServer((req,res)=>{ res.setHeader("Content-type", "text/html;charset=UTF8"); //页面显示的内容 res.write("<h1>hello world!</h1>"); res.write("<ul>"); res.write("<li>Nodejs</li>"); res.write("<li>npm</li>"); res.write("<li>Express</li>"); res.write("<li>Mongodb</li>"); res.write("</ul>"); res.end(); //必须结束,不然本次操做不结束,浏览器显示为载入中 }); server.listen(3000);
写一段程序,证实NodeJS是单线程的:
var http = require("http"); //在服务器外面定义一个变量a var a = 0; var server = http.createServer(function(req,res){ a++; res.end(a.toString()); }); server.listen(3000)
咱们发现不是每一个访问者来了都有新的a值,而是全班共用一个a,每一个人访问的时候看到的都是已经被刷过的a值。
var http = require("http"); var server = http.createServer(function(req,res){ var a = ~~(Math.random() * 1000); if(a == 38){ throw new Error("有人踩地雷了,此人IP:" + req.connection.remoteAddress); } res.end("<h1>"+ a +"</h1>"); }); server.listen(3000)
在Java、PHP或者.net等服务器端语言中,会为每个客户端链接建立一个新的进程。而每一个进程须要耗费大约2MB内存。也就是说,理论上一个8GB内存的服务器能够同时链接的最大用户数为4000个左右。要让Web应用程序支持更多的用户,就须要增长服务器的数量,而Web应用程序的硬件成本固然就上升了。
打个比喻,PHP假如是一个餐馆,那么就是一个这样的餐馆:来一个用户,它就给你新招聘一个服务员,专门伺候你。你点菜的时候,这个服务员帮你点菜,你开始吃了,你这个服务员就闲置。这就形成了大量的浪费,凭什么闲置服务员,为何不去服务别人?
Node.js不为每一个客户链接建立一个新的线程,而仅仅使用一个线程。当有用户链接了,就触发一个内部事件,经过非阻塞I/O、事件驱动机制,让Node.js程序宏观上也是并行的。使用Node.js,一个8GB内存的服务器,能够同时处理超过4万用户的链接。
打个比喻,Node.js假如是一个餐馆,那么就是一个这样的餐馆:总共就一个服务员,A用户来了,帮A用户点菜,B用户来了,B用户稍微被阻塞一下,A点完菜以后,厨师开始作,服务B,B开始点菜,点菜的时候A的菜作好了,给B点完菜以后再去给A端菜,A开始吃,此时C来了,说了句欢迎光临以后,“您看看菜单先”,就去给B端菜去了,B开始吃上了,此时C开始点菜……。
微观上,A、B、C不是并行的,可是宏观上他们是并行的!
另外,单线程的带来的好处,还有操做系统彻底再也不有线程建立、销毁的时间开销。
再来一个案例,用户访问页面的时候,服务器要读取两个文件,此时用console查看惟一的服务员如何工做:
var server = http.createServer((req,res) => { //用户访问的时候执行的语句。 console.log(req.connection.remoteAddress + "进门了!我招呼他去!"); res.setHeader("Content-Type","text/html;charset=UTF8"); console.log(req.connection.remoteAddress + "用户开始读1号文件"); fs.readFile("./test1.txt",(err,data1) => { console.log(req.connection.remoteAddress + "用户读完毕1号文件,开始读2号文件"); fs.readFile("./test2.txt",(err,data2) => { console.log(req.connection.remoteAddress+"用户读完2号文件,开始发送response"); res.write("<h1>" + data1.toString() +"</h1>"); res.write("<h1>" + data2.toString() +"</h1>"); res.end(""); }); }); });
你I/O的时候CPU并无被阻塞,去伺候别人,当别人也I/O了此时执行你的回调函数。
综上所述,nodejs是一个服务员在伺候全部人,因此擅长I/O越多的业务。I/O越多,效率越高,nodejs不会错乱,采用就是事件环机制,也叫事件驱动机制,nodejs不擅长计算多的业务,由于给一个用户计算去了,此时惟一的线程就被阻塞了,其余用户进来就等待。
好比下面的程序,红色的部分是计算水仙花数,计算很复杂,可是是同步的,因此小服务员就被阻塞了:
var server = http.createServer((req,res) => { //用户访问的时候执行的语句。 console.log(req.connection.remoteAddress + "进门了!我招呼他去!"); console.log(req.connection.remoteAddress + "开始计算水仙花数了!"); for(var i = 100 ; i <= 999 ; i++){ // 给三位数拆分红三个单独的数 var ge = i % 10; var shi = parseInt(i / 10) % 10; var bai = parseInt(i / 100); // 计算三次方的和 var sum = Math.pow(ge,3) + Math.pow(shi,3) + Math.pow(bai,3); // 判断输出 if(sum == i){ console.log(req.connection.remoteAddress + "计算出了水仙花数" + i); } } res.setHeader("Content-Type","text/html;charset=UTF8"); console.log(req.connection.remoteAddress + "开始读取文件"); fs.readFile("./test1.txt",(err,data1) => { console.log(req.connection.remoteAddress + "读取文件完毕,开始输出响应流"); res.write("<h1>" + data1.toString() +"</h1>"); res.end(""); }); });
事件驱动是nodejs的底层机制,咱们只需了解nodejs不会“上错菜”,缘由就是事件驱动,有一个事件环。
在Node中,客户端请求创建链接,提交数据等行为,会触发相应的事件。在Node中,在一个时刻,只能执行一个事件回调函数,可是在执行一个事件回调函数的中途,能够转而处理其余事件(好比,又有新用户链接了),而后返回继续执行原事件的回调函数,这种处理机制,称为“事件环”机制。
Node.js底层是C++(V8也是C++写的)。底层代码中,近半数都用于事件队列、回调函数队列的构建。用事件驱动来完成服务器的任务调度,这是鬼才才能想到的。
2013年开始,Nodejs忽然间火爆,由于Nodejs的工做流工具火了!
咱们如今学习nodejs的意义,已经从学习HTTP服务器的构建,变为学习它的工做流工具。
公司的服务器都是PHP、JSP、Python、.net制做的,nodejs作http服务是不多的。可是,每个前端必须会Nodejs,由于以后用的全部的东西webpack、babel、gulp、grunt等等都是基于nodejs的。