第六届360前端星计划_Node.js 基础入门

正则的三个应用场景

主讲人

  • 李喆明
  • 360前端技术专家
  • 奇舞团

从5各方面介绍

  1. 什么是 Node.js
  2. Node.js 基础
  3. NPM
  4. 基于 Node.js 的 Web 开发
  5. Node.js 的调试

1.什么是 Node.js
基于jsv8引擎的js运行时
以js区别:

  • 基于异步 I/O 相关接口
  • 基于 node_modules 和 require 的模块依赖
  • 提供 C++ addon API 与系统交互
    语法一样,提供的接口的差别
  1. Node.js 可以干什么
  • Web 服务端:Web Server、爬虫
  • CLI 命令行脚本:webpack
  • GUI 客户端软件:VSCode、网易云音乐
  • 树莓派IoT, 图像处理, 实时通讯,加密货币...
    例:
    nodejs爬虫
const puppeteer = require('puppeteer');
const url = 'https://movie.douban.com/subject/26794435';

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto(url);
  const film = await page.evaluate(() => {
    const title = $('h1 > span:first-child').text();
    const poster = $('#mainpic img').attr('src');
    const desc = $('span[property="v:summary"]').text().trim();
    return {title, poster, desc};
  });

  console.log(JSON.stringify(film, null, '  '));
  await browser.close();
})();
  1. Node.js 基础
    nodejs 脚本运行
node index.js

读写文件

const fs = require('fs');
fs.readFile('test.txt', (err, data) => {
    console.log(data);
});//异步操作
console.log('read file content');

模块
主要有

  • 内置模块:编译进 Node 中,例如 http fs net process path 等
  • 文件模块:原生模块之外的模块,和文件(夹)一一对应的形式
    使用内部文件
const fs = require('fs');
fs.readFile('a.text', (err, buffer) => {
  console.log(buffer);
})
const {readFile} = require('fs');
readFile('a.txt', (err, buffer) => {
  console.log(buffer);
})

使用文件模块

var circle = require('./circle.js');
console.log('半径为4的圆面积是:' + circle.area(4));

定义模块

const pi = Math.PI;
exports.area = function (r) {
    return pi * r * r;
};
exports.circumference = function (r) {
    return 2 * pi * r;
};

模块加载形式:

require('/foo/bar/a.js');

// 加载相对路径文件
require('../a.js');

// 加载无后缀的文件
require('../a');

// 加载外部模块
require('pkg-name');//从node_modules文件依次查找

模块类型

  • .js
  • .json
  • .node (使用c++形式写完之后,使用node gulp 编译成的二进制文件)
  • .ejs node 新出的基于esmodule 形式 相应的 cjs commonjs导入导出

模块路径查找

  • 绝对路径
  • 相对路径
  • 和当前路径处理为绝对路径
  • 模块/文件夹
  • 原生模块,直接读取缓存
    +[$NODE_PATH, ~/.node_modules, ./node_modules, ../node_modules, ...]
  • 解析 package.json,查找 main 属性,没有则使用 index.js
  • 如果未找到,则报错

js模块解析

const circle = require('./circle.js');


+ require 并不是全局变量
+ 定义的变量 circle 会污染其他文件么?
  • 通过 fs.readFileSync 同步拿到文件内容
    对内容包装,形成闭包 不会影响全局
(function (exports, require, module, __filename, __dirname) {
    var circle = require('./circle.js');
    console.log('The area is ' + circle.area(4));
});
  • 通过 vm.runInThisContext 执行 虚拟沙盒环境
  • 获取 module 对象的值作为模块的返回值
    模块缓存
  • 模块加载后会将返回值缓存起来
  • 下次加载时直接读取缓存结果,避免文件 I/O 和解析时间
  • 导出对象缓存在 Module._cache 对象上
    npm 包管理器


    image.png

    npm最多

包管理

  • 一个package.json文件应该存在于包顶级目录下
  • 二进制文件应该包含在bin目录下
  • JavaScript代码应该包含在lib目录下
  • 文档应该在doc目录下
  • 单元测试应该在test目录下
    例:
    npm init -y
{
  "name": "star-plan",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

meta 信息:

  • main:定义 入口文件
  • npm scripts :运行脚本
  1. dependencies
  2. devDependencies
  3. peerDependencies
  4. bundledDependencies
  5. optionalDependencies
dependencies": {
    "accepts": "^1.2.2",
    "content-disposition": "~0.5.0",
    "cookies": "~0.7.0",
    "debug": "*",
    "delegates": "^1.0.0",
    "escape-html": "~1.0.1",
    "fresh": "^0.5.2",
    "only": "0.0.2",
    "parseurl": "^1.3.0",
    "statuses": "^1.2.0",
    "type-is": "^1.5.5",
    "vary": "^1.0.0"
* ^ ~区别:
^ 可以中版本小版本更新
~小版本跟新
*所有更新到最新
不带
其他形式:
+ 1.0.0 Must match version exactly
+ >1.0.0 Must be greater than version
+ >=1.0.0 <1.0.0 <=1.0.0
+ ~1.0.0 "Approximately equivalent to version"
+ ^1.0.0 "Compatible with version" 
+ 1.2.x 1.2.0, 1.2.1, etc., but not 1.3.0
+ * Matches any version
+ version1 - version2 Same as >=version1 <=version2.
  • bin 指定key-value 在系统中创建alias 直接执行属性名对应文件
  • registry 原代理
    semver version : 版本信息,
    依次:
  • 小版本修复,bug更新
  • 种版本 特性的增加
  • 大版本整体重构
    npm问题(现在被github收购)
  1. 速度问题 官网在国内不好

  2. 安全问题
    解决:

    • 查看源码看 Star
    • https://snyk.io/ 外部的检测服务
    • npm audit (快速检测漏洞)
  3. 基于 Node.js 的Web 开发
    用到http模块

const http = require("http")
const server = http.createServer((req, res) => {
  res.end('Hello World');
});
server.listen(3000);

koa框架

const Koa = require('koa');
const app = new Koa();

// response
app.use(ctx => {
  ctx.body = 'Hello Koa';
});

app.listen(3000);
module.exports = class Application extends Emitter {
  ...

  listen() {
    debug('listen');
    const server = http.createServer(this.callback());
    return server.listen.apply(server, arguments);
  }

  use(fn) {
    this.middleware.push(fn);
    return this;
  }

  callback() {
    const fn = compose(this.middleware);

    if (!this.listeners('error').length) this.on('error', this.onerror);

    const handleRequest = (req, res) => {
      res.statusCode = 404;
      const ctx = this.createContext(req, res);
      const onerror = err => ctx.onerror(err);
      const handleResponse = () => respond(ctx);
      onFinished(res, onerror);
      return fn(ctx).then(handleResponse).catch(onerror);
    };

    return handleRequest;
  }

  createContext(req, res) {
    const context = Object.create(this.context);
    const request = context.request = Object.create(this.request);
    const response = context.response = Object.create(this.response);
    context.app = request.app = response.app = this;
    context.req = request.req = response.req = req;
    context.res = request.res = response.res = res;
    request.ctx = response.ctx = context;
    request.response = response;
    response.request = request;
    context.originalUrl = request.originalUrl = req.url;
    context.cookies = new Cookies(req, res, {
      keys: this.keys,
      secure: request.secure
    });
    request.ip = request.ips[0] || req.socket.remoteAddress || '';
    context.accept = request.accept = accepts(req);
    context.state = {};
    return context;
  }
}

中间件繁多,质量参差不齐,选择困难

  • 逻辑分层
  • 路由处理
  • 数据解析、校验
  • 权限校验
  • Session、Cache
  • 数据库、Redis
  • 安全
  • ...

Koa 无规范约束,不利于企业级团队开发

thinkjs:

基于koa 进行企业级封装 thinkjs

├─src //源码
│  ├─bootstrap 用户启动脚本
│  ├─config //配置文件
│  │  ├─config.js
│  │  └─adapter.js //日志等
│  ├─controller 路由
│  │  ├─index.js //对应着controller 参数和权限
│  ├─logic //
│  │  ├─index.js
│  └─model 数据库操作
├─view 模板文件
│  ├─index_index.html
└─www 静态资源
│  └─static
│     ├─css
│     ├─img
│     └─js
├─development.js 启动文件
├─production.js启动文件
├─package.json
// src/controller/index.js
export default class extends think.Controller {
  indexAction() {
    return this.display();
  }
}

// view/index_index.html
<h3>Hello World</h3>

统一目录
模块统一 模范快速开发,和学习成本小
TODO项目实战

  1. 功能列表
  • TODO List 的页面
  • API
    • 获取 TOO 列表
    • 增加 TODO
    • 删除 TODO
    • 更新 TODO 状态
  1. 数据表设计
CREATE TABLE `todo` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `desc` varchar(255) NOT NULL DEFAULT '',
  `status` tinyint(11) NOT NULL DEFAULT '0' COMMENT '0 是未完成,1是已完成',
  `createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updatedAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  1. 安装 thinkjs
npm install -g think-cli
创建项目
$ thinkjs new todo
$ cd todo
$ npm install
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容

  • 33、JS中的本地存储 把一些信息存储在当前浏览器指定域下的某一个地方(存储到物理硬盘中)1、不能跨浏览器传输:在...
    萌妹撒阅读 2,060评论 0 2
  • 1 Node.js模块的实现# 之前在网上查阅了许多介绍Node.js的文章,可惜对于Node.js的模块机制大都...
    七寸知架构阅读 2,047评论 1 50
  • 1 Node.js模块的实现 之前在网上查阅了许多介绍Node.js的文章,可惜对于Node.js的模块机制大都着...
    zlx_2017阅读 1,215评论 0 1
  • 异步I/O 在Node中,我们可以从语言层面很自然的进行一并I/O操作,每个调用之间无须等待之前的I/O调用结束,...
    Upcccz阅读 511评论 0 2
  • 概要 64学时 3.5学分 章节安排 电子商务网站概况 HTML5+CSS3 JavaScript Node 电子...
    阿啊阿吖丁阅读 9,039评论 0 3