• Nodejs 基础知识 浅析


    1. 模块化

    常用模块化规范

    CommonJS + nodejs

    AMD(Asynchronous Module Definition) + RequireJS

    CMD(Common Module Definition) + SeaJS

    UMD

    ECMAScript 2015 Module

    CMD规范seajs

    1seajs的基础语法:

    引入sea.js插件包

    创建一个test.js文件,在其中写如下代码:

    define(function( require , exports , module ) {

            module.exports.name = ” Tom”

    module模块对象exports对外接口对象(向外暴露数据的方法),name是添加在module模型对象上的属性

            console.log(module.exports === exports) 此处打印结果为true

    也就是exports可以相当于module.exports来使用,但值得注意的是,exports并不是module.exports本身,只是给exports这个变量赋值为module.exports,实现机制类似于:var exports = module.exports

    })

    创建一个main.js文件,在其中写如下代码:

    define(function( require , exports , module ) {

            console.log("hello world")

            console.log(require(‘./test’))

    通过require( )方法,将需要获取数据的文件路径传递进去,如果该文件向外暴露了数据,此处即可获取该数据 { name: “Tom” },如果没有暴露数据,此处打印结果为空对象{ }require无视流程控制语句,只要写了就会加载

    })

    再在页面中创建一个<script>标签,写上seajs.use("./js/main");即上述main.js文件的路径,该文件的.js后缀名写不写都可以,便可执行上述文件中的代码

    2)使用seajs加载第三方插件的兼容写法:(以Zepto为例)

    在Zepto的js文件中,找到定义Zepto的位置:window.Zepto = Zepto

    在这行代码下面添加define函数的兼容写法:

    if( typeof define === ‘function’ &&define.cmd ){

    此处全局判断,文件中是否加载了seajs,因为seajsdefine函数默认添加了cmd属性,如果加载了seajs才引入define函数暴露Zepto,这样可以避免在没有引入seajs时,直接引入Zepto会找不到define方法

                     define(function( require , exports , module ) {

                             module.exports = Zepto;

    }

    }

    2. nodejs 浅析(node:节点)

    nodejs基本介绍(在服务器端使用JavaScript

    (1)JavaScript运行时,构建在chrome V8引擎之上

    (2)是一个JavaScript运行环境

    (3)event-driven 事件驱动

    (4)non-blocking I/O model 非阻塞I/O模型

    (5)包括npm开源库生态系统

    REPL(Read-eval-print-loop):交互式解析器环境

    (1)REPL的常用命令:

           进入node,即进入了REPL环境,在命令窗口输入node

           退出:输入.exit或者连续按ctrl+c两次

           点击tab可以打印出Node.js中的所有对象

           点击向上/向下可以查看历史命令

           .save filename保存输入的命令

           .load filename加载文件

    在REPL环境下,可以用_代替上一次表达式的结果

    (2)REPL中执行js代码文件

    在命令窗口输入node ./nodetest.js  (需要打开的文件路径)

    (3)终端/控制台(命令窗口)基础通用命令

    dir 查看目录中的所有文件

    cd 切换目录   切盘符直接输d:即可

    cls clear screen 清理控制台显示内容

    模块作用域

    nodejs本身是模块化的,具备类似seajs中的moduleexportsrequire使用方法也基本相同,只是不需要写在define中,直接写在js文件内即可,再在需要加载输出内容的文件中使用require请求数据即可

    例如:

    在test.js文件中写:

    module.exports.name = { name: ”Tom” }

    global.obj = { name: ”Jack” }      globalnode提供的类似window的全局对象

    在nodetest.js文件中写:

    console.log( require(‘./test’).name );   require中传入的内容是模块标识,如果是引用同级文件,必须加上./否则会认为是引用的核心模块

    console.log(global.obj);

    在控制台输出:node nodetest.js  输出结果为{ name: ”Tom” }  { name: ”Jack” }

    次案例中,moduleexportsrequire的意义与seajs中基本一致,称为伪全局对象,即在自身模块中有全局效果,每个模块都有这几个对象,用法与seajs中相同,需要注意的是global是node提供的一个全局对象,可以在全局中获取数据,但是存在冲突的可能性,不推荐使用

    node模块中还包含__filename(双下划线)__dirname(双下划线)两个变量,

    __filename当前文件模块的绝对路径,包含当前文件的文件名和后缀

    __dirname当前文件所属的绝对路径,不包含当前文件的文件名和后缀

    全局函数(异步执行函数)

    setTimeout( )、clearTimeout( )、setInterval( )、clearInterval( )

    setImmediate( )、clearImmediate( )

    例如:setTimeout( function(){

                        console.log(“异步执行”);      

    })   即使不传入时间参数,里面的内容也会最后执行,起到异步的作用

    commonJS规范(为JavaScript在后台功能实现定义的API规范nodejs遵循这个规范

    规范特征:

    (1)每个单独的文件都是一个模块

    (2)所有的代码都在自身的模块作用域中运行,不会污染全局作用域

    (3)所有模块的对外接口都是module.exports对象

    (4)require方法用于加载需要调用数据的模块文件

    (5)模块可以多吃加载,但只会在首次加载时运行,并将运行结果进行缓存,以后再加载时,就直接读取缓存结果

    (6)模块加载的顺序,按照其在代码中出现的顺序进行,边加载,边执行

    模块加载

    (1) require查找规则

    1 ) 首先判断标识符是纯字符串还是相对路径

    2 ) 如果是纯字符串:表示核心模块 或者 第三方模块(包)

    3 ) 如果是第三方包:package.json中指定的优先级大于index.js

    4 ) 如果是相对路径,且有扩展名(.js.html等):直接去找对应的文件即可

    5 ) 如果是相对路径,没有扩展名,例如require(‘./test’):,有优先级:test.js > test.json > test.node

    6 ) 如果在当前node_modules找不到:返回上一级目录找

    7 ) 最好使用require(‘path’)模块控制路径,如果直接加载路径,正/、反有时会产生分歧,产生无法加载文件的现象

    (2) 核心模块(node提供的模块)具体功能查看文档

    a ) fs模块(文件操作)

    require(‘fs’).readFile(‘./readme.md’ , function(err , data)){

             console.log(data);  读取传入的文件,以二进制的十六进制形式输出

             console.log(data.toString())   以可视文件形式输出

    }

    b ) os模块(系统操作)

    …….等等

    (2) 加载第三方模块

    a ) 库加载示例:underscore库加载

    使用npm安装underscore库,然后再加载

    加载:require(‘./node_module/underscore/underscore.js’)

    或者不用写路径直接写模块名:require(‘underscore’)

    实现原理是,node在node_module目录下找到underscore文件夹,查看里面的package.json文件,加载这个json文件里面的main属性(指定该包的入口)下的文件路径,这个路径是相对于该package.json文件而言的,也可根据自己需求修改路径

    b ) 自定义库加载

    同理可以按照underscore的思路,将自定义库放在node_module目录下,再在自定义库中创建一个package.json文件,指定main属性的路径到需要加载的文件,最后再require(自定义name’),即可实现加载

    (如果package.json文件中没有main字段,require方法会查找包目录下的index.js , index.json , index.node作为默认入口)

    c ) node中只需在根目录创建唯一node_module目录

    如果当前目录没有node_module目录,node会自动查找上级目录,如果上级也没有,会查找上上级目录,类似JS中函数作用域链,这样带来的好处是,只需要在根目录下创建唯一node_module目录即可,不需要在创建的每个子目录下都创建node_module目录,提高库管理的效率。

    引入库只需执行require(name’)即可

    文件操作("fs”

    (1)编码(字符串与二进制0101…)转换

    a ) node中支持的编码类型(不包含gbk:支持中文的编码规则)

      ascii     早期的编码规则,只支持英文

      utf8     支持不同国家语言的编码规则

      utf16le

      base64

      binary

      hex

    b ) Buffer对象

    Buffer是内存中的一个缓冲区,或者说是内存中的一个数据块

    var buf = new Buffer(2)  创建2个字节的数据块

    buf.write(“a”在上述2字节空间中,用第一个字节写a

    buf.toString()  将16进制显示的Buffer对象转换为字符串显示

    Buffer.concat( [buf1 , buf2 , buf3 , ……] ) Buffer拼接,传入一个Buffer对象的数组

    ……等等 (参考官方文档)

    c ) 解决node中不支持的编码类型

    引入插件包:iconv – lite  具体使用方法查看官方文档

    简单示例:

            var fs = require('fs');

            var iconv = require('iconv-lite');

            var data = iconv.encode('这是一段中文', 'gbk');

            fs.writeFile('./test.txt', data, function(err) {

                if (err) throw err;

            });

            fs.readFile('./test.txt', function(err, data) {

                if (err) throw err;

                console.log(data);  ------  <Buffer d5 e2 ca c7 d2 bb b6 ce d6 d0 ce c4>

                     二进制数据(Buffer类型的对象)

                var str = iconv.decode(data, 'gbk');

                console.log(str);  ------  “这是一段中文”

            })

    (2)同步和异步文件调用

    a ) 同步操作:阻塞I/O操作(input/output)输入/输出端口

    1 ) 会立即执行,阻塞I/O

    2 ) 以同步编码的方式接受返回值

    3 ) 针对同步I/O必须使用try – catch 捕获异常

    4 ) 编程思路简单,易于操作

    5 ) node中的文件操作(fs)API,带sync的都表示同步

     

    b ) 异步操作:非阻塞I/O操作

    1 ) 不会立即执行,会先把任务添加到事件队列,再依次执行

    2 ) 必须通过回调函数的方式接收异步操作的返回值

    3 ) 通过回调函数中的参数err对象,判断是否有错误

    4 ) 相对于同步操作而言,编程思路复杂,不容易操作

    (3)fs文件操作相关API简单示例(查看官方文档)

    读文件  readFilereadFileSync

    写文件  writeFilewriteFileSync

    监视文件  watchFile

    查看文件相关信息  stat

    ……等等

    (4)可读流、可写流

    a ) 可读流

    创建可读流对象:var readStream = require(‘fs’).createReadStream(‘srcRead’)

    通过可读流对象,可以监听文件读取过程,读取过程是通过chunk对象,一点一点进行读取,chunk即是每次读取的文件的大小,读取示例如下:

    读取文件的总字节数:

    var totalSize = require(‘fs’).statSync(‘srcRead’).size

    开始监听文件过程读取:

    readStream.on(‘data’ , function(chunk){

    chunk是一个Buffer对象,具备length属性,length是字节的长度

    由于每次只能读取chunk.length长度的字节,记录总共读取到的文件的大小:

    curSize += chunk.length

    通过curSize/ totalSize,可以获得已经读取的文件的百分比

    })

    读取结束时触发end事件:

    readStream.on(‘end’, function(){

            console.log(“读取结束”)

    }

    b ) 可写流

    创建可读流对象:var writeStream = require(‘fs’).createWriteStream(‘srcWrite’)

    写入数据:writeStream.write(datadata可以是字符串也可以是变量,如果将可读流中的chunk对象,传入可写流方法,可实现大文件的复制

    关闭可写流:writeStream.end( )

    c ) pipe(管道方法)

    创建可读流、可写流对象:

    var readStream = require(‘fs’).createReadStream(‘srcRead’)

    var writeStream = require(‘fs’).createWriteStream(‘srcWrite’)

    可读流具有pipe方法,可直接写入可写流中:

    readStream.pipe(writeStream)

    网络编程

    (1)OSI(Open System Interconnection)开放系统互联模型,将网络通信的工作分为7

    应用层:HTTP、SMTP、IMAP等

    表示层:加密、解密等

    会话层:通信连接、维持会话

    传输层:TCP、UDP

    网络层:IP

    链路层:网络特有的链路接口

    物理层:网络物理硬件

    (2)网络操作(net

    服务器端代码示例:

    var net = require('net');

    创建一个网络服务器:

    var server = net.createServer();

    监听服务器的连接请求,设置请求处理回调函数,只要客户端连接成功就会触发connect连接事件,将当前连接的客户端封装成一个socket对象(双向数据流)

    server.on('connection', function(socket) {

    console.log('客户端连接');

    设置客户端连接:首先启动window的Talnet客户端功能,然后在命令窗口输入telnet 127.0.0.1 3000即可看到客户端的信息,此处为”hello”

        console.log('当前客户端IP地址:'+socket.remoteAddress)

        console.log('当前客户端port端口号:'+socket.remotePort)

        socket.write('hello client');

        socket.on('data', function(data) {

            console.log(data.toString())

        })

    })

    开启服务器,并分配一个端口号进行监听,此处分配端口号3000

    server.listen(3000, function() {

        console.log("server is running")

        console.log("please visit 127.0.0.1:3000")

    });

    客户端代码示例:

    var net = require('net');

    var client = net.createConnection(3000, '127.0.0.1');

    client.on('connect', function() {    创建客户端与服务器的连接

        console.log('connect success');

    })

    client.on('data', function(data) {   data是服务器中socket.write写入的数据

        var data = data.toString();

        console.log(data);

        if (data == "hello client") {

            client.write('hello server');   向服务器中写入数据

        }

    })

    (3)http协议基本概念

    客户端浏览器、服务器连接的简单图示:(以百度为例)

    利用curl查看请求和响应报文: >表示请求报文、<表示响应报文

    下载curl后,配置好环境变量后即可在CMD终端中查看报文

    具体命令:curl www.baidu.com –v

    三次握手

    * Rebuilt URL to: www.baidu.com/

    * Trying 115.239.211.112...  

    * TCP_NODELAY set

    * Connected to www.baidu.com (115.239.211.112) port 80 (#0)

    下述部分是请求报文

    > GET / HTTP/1.1    请求首行:请求方法+请求路径+HTTP协议版本

    > Host: www.baidu.com

    > User-Agent: curl/7.53.1    键值对,包含当前客户端信息

    > Accept: */*

    > 回车换行

    下述部分是响应报文

    < HTTP/1.1 200 OK

    < Server: bfe/1.0.8.18

    < Date: Wed, 01 Mar 2017 02:01:40 GMT

    < Content-Type: text/html

    < Content-Length: 2381

    < Last-Modified: Mon, 23 Jan 2017 13:28:28 GMT

    < Connection: Keep-Alive

    < ETag: "588604fc-94d"

    < Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform

    < Pragma: no-cache

    < Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/

    < Accept-Ranges: bytes

    回车换行

    <!DOCTYPE html>   响应体(index.html中的内容)

    <!--STATUS OK--><html>

    ……

    (4)node中的http模块

    示例代码如下:

    var http = require('http');   

    通过npm安装moment插件,可以获取当前时间

    var moment = require('moment'); 

    var fs = require('fs');

    var server = http.createServer();  创建http服务器

    server.on('request', function(request, response) {

    两个参数request表示请求报文解析成的对象,response表示客户端对象与net中的socket基本相同

        var url = request.url;   requesturl属性,如果没有值,默认为/

        if (url == "/") {

            fs.readFile(require('path').join(__dirname, 'test.html'), 'utf8', function(err, data) {

        response.writeHead(200, {  设置文件类型,可以写text/plain表示任意类型

            'Content-Type': 'text/html;charset=utf-8'

            })

        response.write('当前服务器最新时间是:' + moment().format('YYYY-MM-DD hh:mm:ss'))

        response.end(data);  设置响应结束后的内容,此处渲染test.html

            })

    }

    加载静态资源:

    例如其他的cssjs文件,或者img图片,需要再次发送请求,以css为例,如果test.html页面中有<link rel="stylesheet" href="/css/test.css">则还需在node中加载该文件

    else if (url == "/css/test.css") {

            fs.readFile(require('path').join(__dirname, 'test.html'), 'utf8', function(err, data) {

                          response.writeHead(200, {  设置文件类型为css

                         'Content-Type': 'text/css;charset=utf-8'

                    })

                          response.end(data);  设置响应结束后的内容,此处渲染test.css

                    })

    }

    如果有大量静态资源需要加载,这样重复写else if的方法显然不合适,此时可以通过npm安装mime插件,根据url路径判断Content-Type,方法如下:

    var mime = require('mime'); 

    var url = request.url;

    var statciPath = require('path').join(__dirname, url)  获取静态资源的路径

    fs.readFile(statciPath, 'utf8', function(err, data) {

            if(err){ return response.end(‘404 Not Found’) }   如果资源有错误,报错

    (通过mime中的lookup方法获取资源的Content-Type

            var contentType = mime.lookup(statciPath)  

           response.writeHead(200, { 

                      'Content-Type': contentType

              })

           response.end(data);  

    })

    })

    server.listen(3000, '127.0.0.1', function() {   设置端口号为3000

        console.log('请访问:127.0.0.1')

    })

    (5)安装formidable插件可以对文件上传等操作进行管理

    查考文档:https://www.npmjs.com/package/formidable

  • 相关阅读:
    关于React的入门级安装和最浅显解释
    Node开发文件上传系统及向七牛云存储和亚马逊AWS S3的文件上传
    AWS S3 CLI的安装和配置
    用Node完成AWS S3的Upload流程之全世界最简版
    在Web应用中接入微信支付的流程之极简清晰版
    storm metrics
    hadoop 2.2.0 centos 6.4 x64 编译
    如何打造核心竞争力(经验总结)
    mysql event scheduler机制 与 动态表名创建
    hadoop 2.2.0 安装
  • 原文地址:https://www.cnblogs.com/Tabb/p/6583232.html
Copyright © 2020-2023  润新知