zoukankan      html  css  js  c++  java
  • nodejs 入门

    Node.js 不是一门语言也不是库或框架,而是一个 js运行时环境,简单来说就是 Node 可以解析和执行js代码
    以前只有浏览器的 js 引擎可解析执行 js 代码,后来谷歌浏览器的V8 js引擎被移植出来开发了 Node 这个独立的 js 运行时环境,现在依靠它,js 就可完全脱离浏览器来运行
    但 Node 中的 js 有些不同,没有BOM、DOM,加了很多的服务器级别的API,如文件读写、网络服务构建、网络通信等
     
    官网 的下载版本有两个 ,LTS(Long Term Support)长期支持版,也就是稳定版,Current为体验版,有着最新特性
    下载安装后命令行输入
    node --version  node -v
    即可确认是否安装成功
     
    然后随便创建一个 js 文件,如在F盘新建名为 nodeDemo 的文件夹,在里面新建 helloworld.js,文件名不要使用 node.js , 最好也不要使用中文
    var str = "Hello World~";
    console.log(str);
     
    再在这个 js 文件所在目录打开 DOS 窗口,用 node 文件名 的命令来解析执行对应的文件,此时 helloworld.js 文件就脱离了浏览器,由 Node 执行


    文件读写

    浏览器的 js 是不能对磁盘文件进行操作的,但 Node 中的 js 具有文件操作的能力

    在 nodeDemo 下新建 readFile.js 和 book.txt,book纯文本里内容只有 “ ABC ”

     readFile.js
    var fs = require('fs'); //使用require方法加载fs核心模块
    fs.readFile('./book.txt',function (error,data) { //点表示当前目录,点点是上级目录
        if(error)
            console.log('文件读取失败');
        else
            console.log(data);
    });
    /*readFile()参数有两个,文件路径和回调函数
      回调函数有两个形参,error和data
        读取成功: data为数据, error为null
        读取失败: data为undefined, error为错误对象*/

    fs 是 file system 的简写,文件系统的意思,在 Node 中要进行文件操作就必须引入 fs 这个核心模块,在这个核心模块中,提供了所有文件操作相关的 API,如 fs.readFile 就是用来读取文件的。所有文件操作的API都是异步的

    ABC对应的ASCII十进制为 65 66 67,文件都是以二进制进行存储,这里输出了对应的十六进制。调用 toString 方法即可输出 ABC

    console.log(data.toString());
     

     文件写入也同样简单

    //writeFile()有三个形参:文件路径,文件内容,回调函数
    //写入成功时error为null,失败时为错误对象
    var fs = require('fs');
    fs.writeFile('./song.txt','街灯晚餐',function (error) {
        if(error)
            console.log('文件写入失败');
        else
            console.log('文件写入成功');
    });
    如果写入的文件原本就有内容则会将其覆盖文件如果事先不存在,则会自动创建,但如果这个文件所在的文件夹不存在,则会写入失败
    简单的http服务
    使用 Node 可以很轻松地构建一个 Web 服务器,nodeDemo 目录下创建 http.js
    http.js
    //使用Node可以很轻松地构建一个Web服务器,在Node中专门提供了一个核心模块http
    var http = require('http'); //加载http核心模块
    var server = http.createServer(); //创建一个Web服务器
    
    /*注册request请求事件,当客户端请求时就会触发此事件执行回调函数
      回调函数有两个形参 request和response,表示请求对象和响应对象 */
    server.on('request',function (request,response) {
        console.log('接收到了来自' + request.url + '的请求');
        response.write('Hi~');
        response.end();
        //response对象的write()方法可多次使用但最后一定要用end()来结束响应,否则浏览器会一直等待
        //也可用简单的方式:response.end('Hi~'); 响应的内容只能是二进制Buffer或字符串string
    });
    
    //绑定端口号,启动服务器
    server.listen(5000,function () {
        console.log('服务器启动成功');
    });
    端口号范围从 0 到 65535,qq为4000,tomcat服务器为8080......选个不被占用的端口号即可 
    执行后服务器成功开启,此时程序就占用了 DOS 窗口,等待客户端的请求。这时关闭窗口或 Ctrl+C 则会停止服务器

    通过 ip 可知道是哪台电脑,通过端口号知道是电脑里的哪个程序,而 ip 127.0.0.1 代表本机,所以在浏览器地址栏输入 http://127.0.0.1:5000 可访问刚才创建的服务器

    端口号80是网页服务器默认的访问端口,如果不写端口号 http://127.0.0.1 ,浏览器会默认加上 http://127.0.0.0:80

     

    服务器收到请求,并做出了响应。request.url 获取端口号后面的那一部分路径,代表根目录。如请求 http://baidu.com

    就算末尾不加 / ,浏览器也会默认帮加上

    /favicon.icon 是浏览器默认会请求的 ico 图标

    在这个程序里,无论是请求 /a 还是 /a/b 都会触发 request 事件,从而响应同样的内容
     
    中文乱码

    服务器响应的内容如果有中文,浏览器显示时会出现乱码,这是因为服务器以 utf-8 编码响应数据,而中文浏览器默认以 gbk 编码去解析

    解决办法是设置响应头信息

    var http = require('http');
    var server = http.createServer();
    
    server.on('request',function (request,response) {
        response.setHeader('Content-Type','text/plain;charset=utf-8'); //要放在write()之前
        response.write('Hi~你好啊');
        response.end();
    });
    
    server.listen('3000',function () {
        console.log('Web Server running');
    });

    不同的资源对应不同的 Content-Type ,普通文本是 text/plain,html 是 text/html,更多类型可查看网上的 对照表

    一般只有字符数据才指定编码,图片不需要指定编码 

    response.setHeader('Content-Type','image/jpeg'); 

    核心模块

    Node 为 js 提供了很多服务器级别的API,这些API绝大多数都被包装一个具名的核心模块中

    如文件操作的 fs核心模块、http 服务构建的 http模块path路径操作模块os操作系统信息模块

    用到哪个模块都要必须要用 require() 方法来加载

    Node支持模块化编程,模块分为 具名核心模块(Node内置的模块) 、第三方模块 和 自定义模块(用户自己写的js文件)

     
    Node 中没有全局作用域只有模块作用域,模块作用域简单地说就是文件作用域,超出这个文件的就无法访问

    require() 加载只能是执行模块中的代码,模块是完全封闭的,加载执行多个文件时即便变量重名也不会有污染问题

    如果在浏览器,b.js 的 str 会覆盖前面的 str,所以输出结果应该是 substring,但在这里由于模块作用域,就算 a.js 加载了 b.js,也无法使用 b.js 里的变量或函数

     
    那如何让模块之间进行通信?每个文件模块中都提供了一个 exports 对象,而 require() 方法会返回这个对象,exports 默认是个空对象,即{},可以把外部要访问的成员挂载在此对象中,即通过点语法,为 exports 对象添加属性或方法

     
    require() 有两个作用:执行被加载模块中的代码、得到被加载模块中exports导出接口对象
    exports 导出多个成员
    exports.n = 123
    exports.s = 'Hi'
    exports.f = function(){ console.log('fun') }
    exports.o = { str:'Hello' }

    导出单个成员,如果一个模块需要直接导出某个成员而非挂载的方式,这时候必须使用 module.exports

    module.exports = 'Hi'
    module.exports. = { str:'Hello' }  //同时写的话此字面量对象会覆盖上面的 'Hi' 字符串
    //module.exports如果想导出多个成员,可把放成员放一个对象中
     
    模块原理
    Node 中每个模块内都有一个自己的 module 对象
    module 对象中有一个对象成员叫 exports 
    并且底层代码最后会返回 module.exports,所以谁 require 我,谁就得到 module.exports
    新建一个 test.js 文件,只写一行代码,直接输出 module对象
    test.js
    console.log(module);

     
    Node 底层帮创建了 module对象,所以在 test.js 可以看作有如下代码存在
    var module = {   
      exports:{}  
    }
    
    console.log(module)  //自己写的代码
    
    return module.exports
     
    所以如果需要对外导出成员的话,需要把成员挂载到 module 的 exports 对象中,外部文件通过 require 拿到 exports 对象,便可获取该对象的属性
    var module = {   
      exports:{}  
    }
    console.log(module)  //自己写的代码
    module.exports.name = 'Sam' //通过点语法为exports对象创建name属性,属性值为字符串Sam
    
    return module.exports
     
    但每次都通过 module.exports.xxx 方式有点繁琐,所以 Node 为了简化操作,提供了一个 exports变量,该变量指向 module.exports
    所以 exports === module.exports 为 ture
    var module = {   
      exports:{}  
    }
    var exports = module.exports 
    console.log(module)  
    //module.exports.name = 'Sam' 
    export.name = 'Sam' //两者指向相同,操作的是同一对象
    return module.exports
    可看到 export 和 module.exports ,用哪个都一样,唯一的区别是当导出的是单个成员时只能使用 module.exports,例如想直接返回字符串Sam,而不想把  Sam 放在对象属性中
    此时只能用 module.exports = 'Sam',而不能用 exports = 'Sam' ,因为 module.exports 和 exports 这两个引用存储的是 module 里 exports实例对象 的地址值,赋值后,两者的地址值都会被覆盖,但最后 return 的是 module.exports,而不是 exports   
     
    加载规则 
    模块的加载会优先从缓存中加载

    main 中加载 a , a 里又加载b,当代码回来执行 main 中的 require 时,由于 a 已经加载过 b 了,所以 main 不会再重复加载,可以拿到返回的接口对象但不会再执行代码
    这样做的目的是避免重复加载,底层会优先从缓存中加载,加载模块时会看缓存里有没有,有就用,没有就加载
     
    require方法模块查找机制
    require( ' 模块标识 ' )
    如果模块标识为路径形式,会从给定的路径加载,如果是非路径的标识,就只有两种情况,核心模块或第三方

     
    拿第三方模块 art-template 举栗子,在当前目录用 npm下载好 art-template 后,会有个 node_modules 文件夹
    require('art-template')
    不是路径模块标识,也不是核心模块,所以 Node 会当第三方模块进行加载,先在当前文件所在的目录找到 node_modules 文件夹,然后找            node_modules/art-template    
    node_modules/art-template/package.json

     

    再找 package.json 里的 main 属性,main 记录了 art-template 的入口模块

     

    最终加载的是 index.js 里的内容, index.js 里又要加载其他模块,然后最后导出 template 这个对象。实际上最终加载的还是文件,而核心模块的本质也是文件

    如果 package.json 不存在或 main 指定的入口不存在,则 Node 会自动找到该目录下的 index.js,也就是 index.js 会作为一个默认备选项如果以上条件都不成立,则会进入上一级目录的 node_modules 里查找
    上一级还没有,就继续上上一级查找
    直到当前磁盘根目录还找不到,就会报错:can not find module xxx 
    注意:一个项目有且只有一个 node_modules,放在项目根目录中,这样的话所有子项目都能加载 
     
    更多底层细节,可参考《深入浅出Node.js》中的模块系统章节
  • 相关阅读:
    白色情人节为你身边的程序猿献上一份礼物!
    《大话操作系统——做坚实的project实践派》(3)
    hdu 1085 Holding Bin-Laden Captive!(母函数)
    LeetCode228:Summary Ranges
    android adb端口被占用解决方法
    TortoiseSVN比较工具设置为BeyondCompare 4
    Kotlin Android学习入门
    Android Studio中 ADB WIFI插件进行无线调试实践
    如何离线安装chrome插件
    Androoid studio 2.3 AAPT err(Facade for 596378712): \?C:Users中文文件夹.androiduild-cache
  • 原文地址:https://www.cnblogs.com/Grani/p/9560294.html
Copyright © 2011-2022 走看看