zoukankan      html  css  js  c++  java
  • 前端笔记之NodeJS(一)初识NodeJS&内置模块&特点

    一、NodeJS简介

    NodeJS是开发服务器后台的东西,和PHPJavaEEpython类似,和传统的浏览器的关注DOMJS完全不同,将JavaScript触角伸到了服务器端。内核是Chrome浏览器的V8引擎,解析JavaScript的效率是非常快的。

     创始人。

    在不升级服务器配置的情况下,如何用软件手段来提升服务器性能:Ryan Dahl大致的感觉到了解决问题的关键是要通过事件驱动和异步I/O来达成目的。

    传统的服务器模型:当我们做I/O操作的时候(I表示读,O表示写),CPU被磁盘操作阻塞了,此时我们称这叫做“同步I/Osynchronous I/O),阻塞I/Oblocking I/O)”。

    CPU会经常对磁盘驱动发出I/O命令

    此时磁盘特别忙,CPU就歇着了。造成了资源浪费。上图这种模式叫做“同步I/O”。

    同步(synchronous):当系统遇见了一个需要耗费大量时间的事情的时候,选择死等。
    异步(Asynchronous):当系统遇见了一个需要耗费大量时间的事情的时候,不死等,先做后面的事情,耗时事情做完之后,执行回调函数。

    PHP做一个例子:下面程序中红色部分是I/O操作,此时CPU被阻塞,此时为什么不限做蓝色计算部分?等红色部分做完了用“回调函数”来显示文件内容多好。

    <?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服务器的想象:

    ● 没有历史包袱,没有同步I/O。不会出现一个同步I/O导致事件循环性能急剧降低的情况。

    V8性能足够好,远远比PythonRuby等其他脚本语言的引擎快。

    JavaScript语言的闭包特性非常方便,比C中的回调函数好用。

     创始人Ryan Dahl想到了用V8引擎内核,用JS当做语言去开发服务端程序。

     

    下面是Nodejs的画风,Nodejs不是语言,语言是JavaScriptNodejs是一个平台,让我们的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。紫色语句是回调函数。

    官网:https://nodejs.org/en/

    中文:http://nodejs.cn/

    NodeJS是一个JS运行环境,它构建在chromeV8引擎上。使用了事件驱动、非阻塞I/O模型,使它轻量并且方便。NodeJS有一个全球最大的包生态系统npm

    Node.js使JavaScript的触角伸到了服务器开发中,在Node的世界中,我们关心的不再是用JS操作网页上的DOM、制作交互动画、表单验证……而是服务器端的事情:HTTP请求的处理、GET请求和POST请求、数据库增删改查、cookiesession等等。

     

    Node.js的特点:单线程、非阻塞异步I/O、事件驱动。

    NodejsJS的运行环境,它构建在ChromeV8引擎上。

    Nodejs是一个小极客,追求极致的服务器性能,剑走偏锋的产物。

    与其很多服务员闲着,还不如一个服务员100%的工作。

     


    二、NodeJS的安装

    NodeJSJava虚拟机一样,是跨平台的,也就是说只要写一份代码,可以运行在任何平台上。

    NodeJS官网下载:

     

     

    安装的欢迎界面

     

    同意协议

     

    安装路径全程不能有中文。

    事实上很多软件公司已经去中文化,文档都是英语的文件名,文件夹都是英语的。

     

    这个界面不需要改变任何的配置,但是要知道:这里安装了4个东西。

     

    点击下一步就开始安装了

     

    系统的防火墙,选择是

     

    nodejs已经被成功的安装。

    安装完毕之后,按windows键加R键(run),输入cmd(表示commond命令)按回车:

     

    这是系统的密令提示符,可以输入类似DOS的命令。但是现在要输入

    node -v

    追求以下真理,安装过程,到底发生了什么?发现了一个Nodejs程序:

    我们发现系统的环境变量中,已经添加了这个路径:

    系统的环境变量可以保证我们的node在任意CMD盘符下可以被运行

    nodejswindows中是一个exe程序。


    三、运行Nodejs程序

    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:Usersadmin>中,而是在C: odejs_study,所以要用cd命令来切换光标所在盘符位置:

     

    当用cd切换到01.js所在目录时,此时可以用node命令执行js文件:

     

    也就是说,运行js文件的时候:

    ① 要保证光标所在位置正确

    ② 运行谁,就node谁。

    为了快速打开正确光标所在位置,此时有奇淫技巧:

     

    要求大家,在运行node程序的时候,必须进入准确的盘符,不能使用绝对路径

     

    最快的运行node程序的方法就是使用visual studio code,或者webstrom直接按F5IDE(编程工具)内置的控制台会输出结果。

     

    CMD的命令:
    cls
    清屏。
    
    cd ..
    回退到上一级文件夹
    
    cd 文件夹名字
    进入这个文件夹
    
    dir
    列出当前目录中所有的文件
    
    ↑上箭头
    重复上一条指令。

    四、NodeJS内置模块

    4.1 fs模块

    NodeJS没有自己的语法,JS能写什么,node就能运行什么

    但是要注意,仅限于JS语言核心部分。DOMBOM不能用,node没有浏览器的那些东西

    document.getElementById("box");
    window
    alert()

    但是可以用定时器

    setInterval(function(){
        console.log(Math.random());
    },100)

    ctrl+c可以打断Nodejs程序的执行。

    Nodejs中提供了很多内置模块,帮助我们开发,可以提供浏览器所不具备的功能,模块是内置的,不需要额外安装。从fs内置模块学起,fsfile 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) 第二个参数是回调函数,注意回调函数中提供了两个参数,分别是errdata。注意,nodejs中的所有回调函数的第一个参数都是err对象,表示错误。如果没有错误,这个对象是null

    要会看APIhttps://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());
            });
        });
    });

    4.2 http模块

    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执行在服务器端,语句在服务器被执行、编译,此时发给浏览器的就是执行之后、编译后的纯文本了,不含有计算的。

     

    两个问题:

    1、我用Nodejs搭建的服务器,访问者也必须安装nodejs吗。

    不需要的,因为nodejs是服务器程序,生成的内容仅需要浏览器就能访问

    2、我们用高级ES6语法书写Nodejs程序,必须用高级浏览器访问吗。

    不需要的,因为Nodejs程序不在浏览器执行。

    req表示request用户的请求,访问者的所有必要信息在req中存储,比如

    req.url
    表示访问路径
    req.connection.remoteAddress
    表示访问者的ip地址
    res表示response服务器的响应,服务器应该给与的反馈。
    res.setHeader("Content-type", "text/html;charset=UTF8");
    设置HTTP下行报文体

    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特点

    5.1单线程

    写一段程序,证明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)

    JavaPHP或者.net等服务器端语言中,会为每一个客户端连接创建一个新的进程。而每个进程需要耗费大约2MB内存。也就是说,理论上一个8GB内存的服务器可以同时连接的最大用户数为4000个左右。要让Web应用程序支持更多的用户,就需要增加服务器的数量,而Web应用程序的硬件成本当然就上升了。

    打个比喻,PHP假如是一个餐馆,那么就是一个这样的餐馆:来一个用户,它就给你新招聘一个服务员,专门伺候你。你点菜的时候,这个服务员帮你点菜,你开始吃了,你这个服务员就闲置。这就造成了大量的浪费,凭什么闲置服务员,为什么不去服务别人?

    Node.js不为每个客户连接创建一个新的线程,而仅仅使用一个线程当有用户连接了,就触发一个内部事件,通过非阻塞I/O、事件驱动机制,让Node.js程序宏观上也是并行的。使用Node.js,一个8GB内存的服务器,可以同时处理超过4万用户的连接。

     打个比喻,Node.js假如是一个餐馆,那么就是一个这样的餐馆:总共就一个服务员,A用户来了,帮A用户点菜,B用户来了,B用户稍微被阻塞一下,A点完菜之后,厨师开始做,服务BB开始点菜,点菜的时候A的菜做好了,给B点完菜之后再去给A端菜,A开始吃,此时C来了,说了句欢迎光临之后,“您看看菜单先”,就去给B端菜去了,B开始吃上了,此时C开始点菜……。

     

     微观上,ABC不是并行的,但是宏观上他们是并行的!

     另外,单线程的带来的好处,还有操作系统完全不再有线程创建、销毁的时间开销。

     


    5.2异步I/O特性

    再来一个案例,用户访问页面的时候,服务器要读取两个文件,此时用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("");
         });
    });

    5.3事件驱动

    事件驱动是nodejs的底层机制,我们只需了解nodejs不会“上错菜”,原因就是事件驱动,有一个事件环。

    Node中,客户端请求建立连接,提交数据等行为,会触发相应的事件。在Node中,在一个时刻,只能执行一个事件回调函数,但是在执行一个事件回调函数的中途,可以转而处理其他事件(比如,又有新用户连接了),然后返回继续执行原事件的回调函数,这种处理机制,称为“事件环”机制。

    Node.js底层是C++V8也是C++写的)。底层代码中,近半数都用于事件队列、回调函数队列的构建。用事件驱动来完成服务器的任务调度,这是鬼才才能想到的。

     

     

    2013年开始,Nodejs突然间火爆,因为Nodejs的工作流工具火了!

    我们现在学习nodejs的意义,已经从学习HTTP服务器的构建,变为学习它的工作流工具。

    公司的服务器都是PHPJSPPython.net制作的,nodejshttp服务是很少的。但是,每一个前端必须会Nodejs,因为之后用的所有的东西webpackbabelgulpgrunt等等都是基于nodejs的。


  • 相关阅读:
    layui框架如何在停止服务用户操作任何步骤自动跳转登录页
    h5移动端和ios以及安卓客户端的接口联调
    sublime 主要使用方法
    内外边距、浮动、布局相关
    js介绍
    css的三个特性 背景透明设置
    选择器 导航制作相关
    表单综合
    自定义列表dl
    相对路径和绝对路径
  • 原文地址:https://www.cnblogs.com/rope/p/10724604.html
Copyright © 2011-2022 走看看