Nodejs in action 总结(一)

node基本概念

什么是node?

node源于js的流行,因而出现性能极强的V8。Node是JavaScript程序的平台,不要把它跟框架相混淆。很多人都误把Node当做JavaScript 上的Rails或Django,实际上它更底层。

使用node开发服务端的几个好处

  • 减少客户端服务端的语言切换,实现代码共享
  • JSON是JavaScript原生支持格式
  • 有些NoSQL数据库(MongoDB和CouchDB)用的就是js
  • js是一门编译目标语言,很多语言可以编译成js
  • Node用的虚拟机(V8)紧跟ECMAScript标准
  • Node非常适合数据密集实时型系统(data-intensive real-time)

Node的异步IO原理图

image

基本模块

除了实现宿主环境(浏览器)中的一些常用对象,Node还有一组用来处理多种网络和文件I/O的核心模块。 其中包括用于HTTP、 TLS、 HTTPS、文件系统(POSIX) 、数据报(UDP)和NET(TCP)的模块。这些核心模块刻意做得很小、底层并且简单,只包含要给基于I/O的程序用的组成部分。第三方模块基于这些核心模块,针对常见的问题进行了更高层的抽象。

Node编程基础

Node新手两大基本问题:

  • 如何组织代码
  • 如何异步逻辑顺序执行

如何组织代码

Node模块采用CommonJS 模块规范

路径引用

image

关于require和同步

require是Node中少数几个同步I/O操作之一。因为经常用到模块,并且一般都是在文件顶端引入,所以把require做成同步的有助于保持代码的整洁、有序,还能增强可读性。但在程序中I/O密集的地方尽量不要用require。所有同步调用都会阻塞Node,直到调用完成才能做其他事情。比如你正在运行一个HTTP服务器,如果在每个进入的请求上都用了require,就会遇到性能问题。所以通常都只在程序最初加载时才使用require和其他同步操作。

用node_modules重用模块

Node中有一个独特的模块引入机制, 可以不必知道模块在文件系统中的具体位置。这个机制就是使用node_modules目录。
如果引用模块并未告知模块位置,require(common.js)则采用以下的方法来搜寻这个模块。

是否核心->递归向上查找node_modules目录->环境变量NODE_PATH->抛出异常

注意

  1. 引用本地文件夹指定输出文件


    image
  2. 模块多引用缓存(monkey patching)
    Node能把模块作为对象缓存起来。 如果程序中的两个文件引入了相同的模块, 第一个文件会把模块返回的数据存到程序的内存中, 这样第二个文件就不用再去访问和计算模块的源文件了。实际上第二个引入有机会修改缓存的数据。这种“猴子补丁” (monkey patching)让一个模块可以改变另一个模块的行为,开发人员可以不用创建它的新版本。

异步编程技术

概念

事件会触发响应逻辑,在node世界里,存在两种:回调与事件监听
回调通常用来定义一次性、单个响应的逻辑。事件监听本质上也是回调,不同的是,它跟一个概念实体(事件)相关联,能添加多个响应实体。

一个Node HTTP服务器实例就是一个事件发射器,一个可以继承、能够添加事件发射及处理能力的类(EventEmitter) 。
Node的异步回调惯例:Node中的大多数内置模块在使用回调时都会带两个参数:第一个是用来放可能会发生的错误的,第二个是放结果的。

    var fs = require('fs'); 
    fs.readFile('./titles.json', function(er, data) {
       if (er) throw er;   // do something with data if no error has occurred 
       }); 

异步逻辑的顺序化

让一组异步任务顺序执行的概念被Node社区称为流程控制。这种控制分为两类:串行和并行。

image

串行流程控制
可以使用一堆嵌套回调,但是可读性差。
使用第三放库,如Nimble。
TODO:underscore,backbone
并行流程控制
社区中的很多附加模块都提供了方便好用的流程控制工具。其中比较流行的有Nimble、Step 和Seq三个。

Node Web

image

基本用法:

const http = require('http')
//req,res均为数据流,详情见http模块
const server = http.createServer((req,res)=>{
    res.end('Hello World')
})
server.listen(3000)

构建RESTful Web服务

RESTful Web服务,一个使用HTTP方法谓词提供精简API的服务。

POST(其余暂略)

const http = require('http')
const server = http.createServer((req, res) => {
    // node的http解析器读入并解析请求数据时,会将数据解析成data事件的形式
    // 只要读入了新的数据块,就会触发data事件
    // data事件会提供Buffer对象,这是Node版的字节数组。最好将流编码设定为ascii或utf8;这样data事件会给出字符串
    req.setEncoding('utf8')
    req.on('data',(chunk) => {
    })
    req.on('close',() => {
        res.end()
    })
})

设定Content-Length头
为了提高响应速度,如果可能的话,应该在响应中带着Content-Length域一起发送。设定Content-Length域会隐含禁用Node的块编码,因为要传输的数据更少,所以能提升性能。
res.setHeader('Content-Length,Buffer.byteLength(body))`

Content-Length的值应该是字节长度,不是字符长度,并且如果字符串中有多字节字符,两者的长度是不一样的。为了规避这个问题,Node提供了一个Buffer.byteLength()方法。

用formidable处理上传的文件

提供静态文件服务

通过管道,将req需要的文件,读入输入流,管道到res输出流。

res.setHeader('Content-Lenght',stat.size)
let stream = fs.createReadStream(path)
stream.pipe(res)
stream.on('error',(err)=>{
    sendResult(res, 500,'Internal Server Error');
})

存储Node程序中的数据

选择合适的存储机制取决于以下五个因素:

  • 存储什么数据;
  • 为了保证性能,要有多快的数据读取和写入速度;
  • 有多少数据;
  • 要怎么查询数据;
  • 数据要保存多久,对可靠性有什么要求。

为此,一般有三种选择:

  • 存储数据而无需安装和配置DBMS:文件、内存(并发问题)
  • 用关系型数据库存储数据,具体说就是MySQL和PostgreSQL
  • 用NoSQL数据库存储数据,具体说就是Redis、MongoDB和Mongoose

关系型数据库管理系统

var http = require('http')
var work = require('./lib/timetrack')
var mysql = require('mysql')
var qs = require('querystring')
// 1.创建数据库
var db = mysql.createConnection({
    host:'127.0.0.1',
    user:'myuser',
    password:'mypassword',
    database:'timetrack',
    port:3000
})
// 2.创建server
var server = http.createServer((req,res)=>{
    switch(req.method){
        case 'POST':
            switch(req.url){
                case '/':
                    // 一般是路由函数,内部会有一些解析请求的辅助函数,用于实现模块化
                    work.add(db,req,res)
                    break
                case 'archive':
                    work.archive(db,req,res)
                    break
                case 'delete':
                    work.delete(db,req,res)
                    break
            }
            break
        case 'GET':
            switch(req.url){
                case '/':
                    work.show(db,res)
                    break
                case 'archive':
                    work.archive(db,res)
            }
            break
    }
})
// 3.初始化数据库,建表
db.query(
    "GREATE TABLE IF NOT EXISTS work ("
    + "id INT(10) NOT NULL AUTO_INCREMENT, "
    + "hours DECIMAL(5,2) DEFAULT 0, "
    + "date DATE, "
    + "archived INT(1) DEFAULT 0, "
    + "description LONGTEXT, "
    + "PRIMARY KEY(id)",
    (err) => {
        if(err) throw err
        console.log('Server started...')
        server.listen(3000,'127.0.0.1')
    }
)

MongoDB & Redis

尽管关系型DBMS为可靠性牺牲了性能,但很多NoSQL数据库把性能放在了第一位。因此,对于实时分析或消息传递而言,NoSQL数据库可能是更好的选择。NoSQL数据库通常也不需要预先定义数据schema, 对于那种要把数据存储在层次结构中, 但层次结构却会发生变化的程序而言,这很有帮助。

Redis

Redis非常适合处理那些不需要长期访问的简单数据存储,比如短信和游戏中的数据。教程尝试Redis是个很好的起点。要深入学习如何使用Redis,请看Josiah L. Carlson的Redis in Action一书(Manning, 2013)。

MongoDB

MongoDB数据库把文档存在集合(collection)中。它们不需要相同的schema,每个文档都可以有不同的schema。 这使得MongoDB比传统的RDBMS更灵活,因为你不用为预先定义schema而操心。


image

Mongoose

MongoDB是一个强大的数据库,而node-mongodb-native提供了高性能的MongoDB访问,但你可能想用一个抽象的数据库访问API,在底层帮你处理细节。这可以让你加快开发速度,同时维护更少的代码。这些API中最流行的是Mongoose。
Mongoose的模型(模型视图控制器中的说法)提供了一个到MongoDB集合接口,以及一些实用的功能,比如schema层次结构,中间件以及数据校验。 schema层次结构可以让一个模型跟其他模型关联,比如说,让一篇博客文章包含相关的评论。中间件可以转换数据,或在操作模型数据的过程中触发逻辑,让删除父数据时对子数据的修剪这样的任务变成自动化的。 Mongoose的校验支持让你可以在schema层面决定什么样的数据是可接受的,而不是必须手工处理它。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容

  • 面试题一:https://github.com/jimuyouyou/node-interview-questio...
    R_X阅读 1,618评论 0 5
  • mongoose入门 MongoDB是一个开源的NoSQL数据库,相比MySQL那样的关系型数据库,它更显得轻巧、...
    huilegezai阅读 4,450评论 0 14
  • 原文地址 本文简单的介绍了数据库,以及如何在 Node/Express 中应用他们。之后展示如何使用Mongoos...
    前端幼儿班阅读 5,163评论 1 5
  • 原文链接:https://github.com/jimuyouyou/node-interview-questio...
    R_X阅读 9,465评论 0 26
  • MongoDB 1. MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用...
    Kevinr阅读 1,560评论 0 3