zoukankan      html  css  js  c++  java
  • 突袭HTML5之WebSocket入门2 高效服务器Node.js

        JavaScript脱离浏览器的限制以后,隐隐有再次走向光明的迹象,看来还得重新审视一下它的前景。由于条件有限,这里所有的例子是运行在Windows平台下的。而且由于目前并没有太好的组织JS程序的IDE工具,所以使用VS2010的WebSite类型建立了一个空的Web,方便组织文件和文件夹。
    node.js
        node.js(简称为Node)不是JavaScript应用、而是JavaScript运行平台
        Node从2009年诞生至今,已经发展了两年有余,其成长的速度有目共睹。从在github的访问量超过Rails,到去年底Node创始人Ryan Dalh加盟Joyent获得企业资助,再到发布Windows移植版本,Node的前景获得了技术社区的肯定。

        Node采用C++语言编写而成;为什么采用C++语言呢?据Node创始人Ryan Dahl回忆,他最初希望采用Ruby来写Node,但是后来发现Ruby虚拟机的性能不能满足他的要求,后来他尝试采用Google的V8引擎,所以选择了C++语言。Node是一个服务器端的JavaScript运行环境(支持的系统包括*nux、Windows),这意味着你可以编写系统级或者服务器端的JavaScript脚本,交给Node来解释执行。

    程序安装

        到主站http://nodejs.org/下载系统对应的最新版的装上即可,非常简单。安装程序会自动安装npm,这个就是Node的模块管理工具(就像Ruby的Gem一样),所有扩展的模块或框架都是通过这个安装的。

    Node模块 

        模块是Node可用的类库;Node使用CommonJS模块系统作为核心模块,比如http, sys, process, fs, streams...来完成各种功能。用户可以自己编写模块,在程序中使用;此外,目前有大量稳定的外部模块可用,基本都可以在https://github.com/joyent/node/wiki/modules看到介绍;使用npm install可以安装模块相应的模块到当前目录中,比如经典的socket.io, express,是通过下面的命令行执行安装的:

    npm install socket.io express

        在Node中,文件和模块是一一对应的。

    卓越特性

        Node的特性可以概括如下:Google V8,单线程,非阻塞IO,事件驱动。 

        先说V8,Google Chrome浏览器的JavaScript引擎Google V8是一个开源的独立引擎,可独立运行或内嵌于任何C++工程之中,性能很好,同时还提供了很多系统级的API如文件操作、网络编程等。速度是V8追求的主要设计目标之一,它把JavaScript脚本直接编译成机器码运行,比起传统的“中间代码+解释器”的引擎,优势不言而喻,这就是Node高效的一个重要原因。浏览器端的JavaScript脚本在运行时会受到各种安全性的限制,对客户系统的操作有限。相比之下,Node则是一个全面的后台运行时,为JavaScript提供了其他语言能够实现的许多功能。Node的目的是提供一种简单的途径来编写高性能的网络程序。

        Node是单线程执行的,那么如何解决并行的问题呢?这个就是通过非阻塞IO与事件驱动实现的。 这种做法的的根据是IO的运行速度远远慢于CPU的运行速度,所以当请求来了以后,CPU处理一下,直接甩给相应的IO去处理,然后继续等待别的请求。最经典的一句解释就是“除了你的代码,其他全部是并行执行的”。下面这幅图清晰的说明了Node的并行处理机制:

        Node核心模块中的方法基本都有异步版本与同步版本(Sync结尾的方法),尽量不要使用同步的版本来阻塞主线程。

    编程实践

        Node大大简化了Web开发人员的工作量,只需要少少几步,就可以搭建起一个服务器,进行开发和调试。

    • 服务端编程

        服务器编程就是启动服务器,处理客户端请求。下面就是一个附带简单路由功能的服务器程序: 

    //导入需要的模块
    var http = require("http"), url = require("url"), path = require("path"),  fs = require("fs"); 
    //创建Server并处理请求
    http.createServer(function (req, res) 
    {     
        var pathname=__dirname+url.parse(req.url).pathname;     
        if (path.extname(pathname)=="") 
        {        
            pathname+="/";     
        }     
     
        if (pathname.charAt(pathname.length-1)=="/")
        {         
            pathname+="index.html";     
        }      

        path.exists(pathname,function(exists)
        {         
            if(exists)
            {            
                switch(path.extname(pathname))
                {                 
                    case ".html":                     
                        res.writeHead(200, {"Content-Type": "text/html"});                     
                        break;                 
                    case ".js":                     
                        res.writeHead(200, {"Content-Type": "text/javascript"});                     
                        break;                                
                    case ".png":                     
                        res.writeHead(200, {"Content-Type": "image/png"});                  
                        break;               
                    default:                   
                        res.writeHead(200, {"Content-Type": "application/octet-stream"});      
                }         
                        
                fs.readFile(pathname,function (err,data)
                {               
                    res.end(data);            
                });       
            } 
            else 
            {     
                res.writeHead(404, {"Content-Type": "text/html"});          
                res.end("<h1>404 Not Found</h1>");     
            }    
            });   
    }).listen(8080, "127.0.0.1");   
                        
    console.log("Server running at http://127.0.0.1:8080/"); 

        运行这个服务程序很简单,把这个代码保存为server.js(名字随意),然后直接在cmd中执行"node server.js",这样一个服务端程序就就绪了,是不是很简单!

    注意

    1. node后面的参数一定要带扩展名,不能省略那个".js",否则会报错。

    2. 这是一个简单的服务器程序,所以没有考虑程序的结构;在典型的开发过程中,通常需要把启动代码,服务器代码,路由代码,请求处理代码分别放到不同的模块中并使用MVC来减弱每个功能之间的耦合性,易于扩展。例如下面的代码结构:

    |-Solution文件夹

        |--index.js:程序的入口,放置启动服务器等初始化方法(Node的惯用法,也可使用run.js等名字)。

        |--server.js:程序服务器程序,通常放置启动服务器,调用路由程序(这个有时也放到index.js中)等。

        |--route.js:程序路由程序,放置路由方法。

        |--config.js:配置路由程序。

        |--controllers:放置各种需求处理的业务逻辑。

            |--hanlerRequest.js:请求处理程序模块,放置每种请求的处理方法。

        |--models:放置各种需要的数据

            |--model...业务数据

        |--views:放置各种页面模板

            |--index.html:页面模板

        这里的组织方式只是我采用的一个组织方式,实际开发中还是以个人的实际需要来设计自己的组织方式。

    3. 模块的成员使用exports或者this导出。例如服务器程序server.js:

    var http = require("http");
       
    exports.runServer = function(){
        var server = http.createServer(function(req, res){
           //...        
        }).listen(8080);
        
        console.log('Server running at http://127.0.0.1:'+ port +'/');
    };

    this.server = '127.0.0.1';

        server.js模块导出了runServer方法,server属性。

    4. 导入模块用require方法,导入以后可以直接使用导入的成员。例如index.js模块的代码为:

    var server = require('./server');
    server.runServer();

    导入的规则如下:

    (1)核心模块通过标示符直接导入,而且总是被优先加载。例如,require('http')将总是返回内建的HTTP模块,即便又一个同名文件存在。

    (2)文件模块通过文件名导入(可以省略扩展名),如果没有找到确切的文件名,Node将尝试以追加扩展名.js后的文件名读取文件,如果还是没有找到则尝试追加扩展名.node。.js文件被解释为JavaScript格式的纯文本文件,.node文件被解释为编译后的addon(插件)模块,并使用dlopen来加载。

    (3)以'/'为前缀的模块是一个指向文件的绝对路径,例如require('/home/publish/foo.js')将加载文件/home/publish/foo.js。
    (4)以'./'为前缀的模块是指向文件的相对路径,相对于调用require()的文件。也就是说为了使require('./circle') 能找到正确的文件,circle.js必须位于与foo.js 相同的路径之下。
    (5)如果标明一个文件时没有 '/' 或 './'前缀,该模块或是"核心模块",或者是位于安装目录的node_modules目录中。如果在其他的目录下运行npm安装模块,则这里指的就是其他目录的node_modules目录。

    (6)在Node中,require.paths是一个保存模块搜索路径的字符串数组。当模块不以'/','./'或'../'为前缀时,将从此数组中的路径里进行搜索。可以在运行时改变require.paths数组的内容,以改变路径搜索行为。但在实践中发现,修改require.paths列表往往是造成混乱和麻烦的源头。

    • 客户端编程

        Node运行服务端程序,不影响客户端,客户端编程还是与以前一样,就是考验兄弟JavaScript/JQuery的功力了。

    实用参考:

    Node核心模块介绍:http://cnodejs.org/cman/

    Node入门经典教程:http://www.nodebeginner.org/index-zh-cn.html#responding-request-handlers-with-non-blocking-operations 

  • 相关阅读:
    PHP在yii2中封装SuperSlide 幻灯片编写自己的SuperSlideWidget的例子
    安卓界面控件屏幕居中Layout例子
    java web的开发 知识要点
    PHP MVC简单介绍,对PHP当前主流的MVC做了一个总结
    自己编写的一个有关安卓应用开发培训PPT
    springboot配置fastjson后端往前端传输格式化
    实现商城商品秒杀分析
    idea添加jdbc包
    idea心得
    gc overhead limit exceeded内存问题
  • 原文地址:https://www.cnblogs.com/dxy1982/p/2326131.html
Copyright © 2011-2022 走看看