3

Node.js是什么

官网定义:

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。 Node.js 使用了一个事件驱动、非阻塞式I/O 的模型,使其轻量又高效。

非阻塞 I/O 模型(non-blocking I/O model),简单点讲就是每个函数都是异步的,最后由 Libuv 这个 C/C++ 编写的事件循环处理库来处理这些 I/O 操作,隐藏了非阻塞 I/O 的具体细节,简化并发编程模型,让你可以轻松的编写高性能的Web应用,所以它是轻量(lightweight)且高效(efficient)的。

Node.js能做什么

clipboard.png

1)跨平台:覆盖你能想到的面向用户的所有平台,传统的PC Web端,以及PC客户端 nw.js/electron 、移动端 cordova、HTML5、react-native、weex,硬件 ruff.io 等
2)Web应用开发:网站、Api、RPC服务等
3)前端:三大框架 React Vue Angular 辅助开发,以及工程化演进过程(使用Gulp /Webpack 构建 Web 开发工具)
4)工具:npm上各种工具模块,包括各种前端预编译、构建工具 Grunt / Gulp、脚手架,命令行工具,各种奇技淫巧等

Node核心:异步流程控制

clipboard.png

其实,一般使用是不需要掌握上图中的所有技术的。对于初学者来说,先够用,再去深究细节。所以,精简一下,只了解3个就足够足够用了。
clipboard.png

Promise 的最大优势是标准化,各类异步工具库都按照统一规范实现,即使是async函数也可以无缝集成。所以用 Promise 封装 API 通用性强,用起来简单,学习成本低。在async函数普及之前,绝大部分应用都是采用Promise来做异步流程控制的,所以掌握Promise是Node.js学习过程中必须要掌握的重中之重。

推荐学习资料
Node.js最新技术栈之Promise篇 https://cnodejs.org/topic/560...
理解 Promise 的工作原理 https://cnodejs.org/topic/569...
Promise 迷你书 http://liubin.github.io/promi...

异步和事件触发:浏览器

浏览器中非阻塞I/O的例子
clipboard.png

异步和事件触发:服务器

Node中的非阻塞I/O示例
clipboard.png

Node基于libuv实现跨平台的架构示意图

clipboard.png

Commonjs, AMD, CMD规范

CommonJS

  • 通过 require 来加载模块。
  • 通过 exports 和 modul.exports 来暴露模块中的内容。
// moduleA.js
module.exports = function( value ){
return value * 2;

// moduleB.js
var multiplyBy2 = require('./moduleA');
var result = multiplyBy2(4);

CommonJS是同步加载模块,服务器端的Node.js遵循CommonJS规范。

require("module");
require("../file.js");
exports.doStuff = function() {};
module.exports = someValue;

AMD
AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义"。AMD规范其实只有一个主要接口 define(id,dependencies,factory),它要在声明模块的时候指定所有的依赖dependencies,并且还要当做形参传到factory中,对于依赖的模块提前执行,依赖前置。

define("module", ["dep1", "dep2"], function(d1, d2) {
  return someExportedValue;
});
require(["module", "../file"], function(module, file) { /* ... */ });

CMD
CMD规范和AMD相似,尽量保持简单,并且与CommonJS和NodeJS的Modules规范保持了很大的兼容性。依赖就近,延迟执行。

define(function(require, exports, module) {
  var $ = require('jquery');
  var Spinning = require('./spinning');
  exports.doSomething = ...
  module.exports = ...
})

Node查找模块的步骤

clipboard.png

中间件

中间件组件是一个JavaScript函数,按惯例会接受三个参数:一个请求对象, 一个响应对象,还有一个通常命名为next的参数,它是一个回调函数,表明这个组件已经完成了它的工作,可以执行下一个中间件组件了。

Connect
最小的Connect程序

var connect = require('connect');
var app = connect();
app.listen(3000);

日志中间件

var connect = require('connect');

function logger(req, res, next) {
  console.log('%s %s', req.method, req.url);
  next();
}

function hello(req, res) {
  res.setHeader('Content-Type', 'text/plain');
  res.end('hello world');
}

connect()
  .use(logger)
  .use(hello)
  .listen(3000);
  

中间件的顺序很重要

用中间件的顺序执行认证

var connect = require('connect');
connect()
  .use(logger)
  .use(restrictFileAccess)
  .use(serveStaticFiles)
  .use(hello)
  .listen(3000);

挂载中间件和服务器

路由admin请求

function admin(req, res, next) {
  switch (req.url) {
    case '/':
      res.end('try /users');
      break;
    case '/users':
      res.setHeader('Content-Type', 'application/json');
      res.end(JSON.stringify(['tobi', 'loki', 'jane']));
      break;
  }  
}

挂载中间件或服务器

var connect = require('connect');
connect()
  .use(logger)
  .use('/admin', restrict)
  .use('/admin', admin)
  .use(hello)
  .listen(3000);

创建可配置中间件

function setup(options) {
  //  设置逻辑
  
  return function(req, res, next) {
    // 中间件逻辑
  }
}

app.use(setup({some: 'options'}));

创建可配置的logger中间件组件

var app = connect()
  .use(logger(':method :url'))
  .use(hello);

构建路由中间件组件

var connect = require('connect');
var router = require('./middleware/router');
var routes = {
  GET: {
    '/users': function(req, res) {
      res.end('tobi, loki, ferret');
    },
    '/user/:id': function(req, res, id) {
      res.end('user ' + id);  
    }
  },
  DELETE: {
    '/user/:id': function(req, res, id) {
       res.end('deleted user ' + id);
     }
  }
};

connect()
  .use(router(routes))
  .listen(3000);

因为程序里中间件的数量没有限制,中间件组件使用的次数也没有限制,所以在一个程序中 有可能会定义几个路由器。

var connect = require('connect');
var router = require('./middleware/router');

connect()
  .use(router(require('./routes/user')))
  .use(router(require('./routes/admin')))
  .listen(3000);

使用错误处理中间件

var connect = require('connect')

connect()
  .use(function hello(req, res) {
    foo();
    res.setHeader('Content-Type', 'text/plain');
    res.end('hello world');
  })
  .listen(3000);

默认情况下,Connect给出的响应是状态码500,包含文本“Internal Server Error”以及错误自 身详细信息的响应主体。

function errorHandler() {
  var env = process.env.NODE_ENV || 'development';
  return function(err, req, res, next) {
    res.statusCode = 500;
    switch (env) {
      case 'development':
        res.setHeader('Content-Type', 'application/json');
        res.end(JSON.stringify(err));
        break;
      default:
        res.end('Server error);
    }
  }
}

Connect自带的中间件

  • cookieParser(): 解析HTTP cookie
  • bodyParser(): 解析请求主体
  • limit(): 请求主体的限制
  • query(): 查询字符串解析
  • logger(): 记录请求
  • session(): 会话管理
  • static(): 静态文件服务

数据存储
内存, redis, mysql, mongodb, mongoose

express

渲染视图
处理表单和文件上传

koa

egg

部署

阿里云,腾讯云,域名,pm2,nginx,集群,分布式,docker,微服务


刘欢
46 声望2 粉丝

« 上一篇
前端知识总结