Practical Node.js摘錄(2018版)第1,2章。

大神的node書,免費javascript

視頻:https://node.university/courses/short-lectures/lectures/3949510css

另外一本書:全棧JavaScript,學習backbone.js node.js and MongoDB. html

 

1,2章: 前端

  1. Setting up Node.js and Other Essentials [2nd Edition]
  2. Using Express.js 4 to Create Node.js Web Apps [2nd Edition]

第一章

  • Node.js and npm (Node package manager) installation
  • Node.js script launches
  • Node.js syntax and basics
  • Node.js integrated development environments (IDEs) and code editors
  • Awareness of file changes
  • Node.js program debugging

Key Differences Between Node and Browser JavaScript

node沒有window, 所以也就沒有document對象模型,沒有DOM,沒有hierarchy of element。java

node有global object.(小寫字母),能夠在任何node環境,文件,app中使用。node

你能夠在global object上建立property,同時它也有內建的properties。這些properties也是global的,所以能夠用在anywhere。git

在browser,有內建的modules。github

可是node沒有core modules,經過文件系統可使用各類modules。web

 


 

REPL

進入node控制檯,直接在terminal輸入node, 這是一個virtual 環境,一般稱爲read-eval-print-loopajax

能夠直接執行Node.js/JavaScript代碼。

⚠️:

require()方法,是node.js的modules功能,在chrome browser 控制檯上會報告❌ReferenceError。

 


 

 

Launching Node.js Scripts

語法:

node filename

node -e "直接輸入javaScript代碼"
//如$ node -e "console.log(new Date())

 

參數e, 是evaluate script, -e, --eval=...

 


 

 

Node.js Basics and Syntax

 

Node.js使用chrome v8引擎和ESCAScript,所以大多數語法和前端js相似。

 

  • Loose typing
  • Buffer—Node.js super data type
  • Object literal notation
  • Functions
  • Arrays
  • Prototypal nature
  • Conventions  

Loose Typing

大多數時候支持自動typecasing。primitives包括:String, Number, Boolean, Undefined, Null。

Everything else is an object。包括:Class, Function, Array, RegExp。

在Js,String, Number, Boolean對象有幫助方法:

//例子:
'a' === new String('a')   //false,  由於使用new String會返回對象
//因此用toString()
'a' === new String('a').toString()   // true
//或者使用==,執行自動typecasing, ===加入了類型判斷

 

 

Buffer—Node.js Super Data Type

Buffer是Node.js增長的數據類型。

它是一個有效的數據存儲data store.

它功能上相似Js的ArrayBuffer。

⚠️:(具體內容,如何建立,使用未看。)

 

 

Object Literal Notation對象字面量符號

Node8之後的版本都支持ES6。

好比,箭頭函數,使用class, 能夠extend另外一個對象{...anotherObject}, 動態定義屬性名,使用super()關鍵字,使用函數的短語法。

 

Functions

在Node.js,函數最重要,它們是對象!能夠有屬性。

使用function expression定義一個函數,能夠anonymous。例子:

//outer 'this'
const f = () => {
//still outer "this" console.log(
'Hi') return true }

 

JavaScript把函數當成對象,因此函數也能夠做爲參數傳遞給另外一個函數,嵌套函數會發生callbacks。

 

Arrays

let arr4 = new Array(1,"Hi", {a:2}, () => {console.log('boo')})
arr4[3]() // boo

 從Array.prototype,global object繼承了一些方法。

 

Prototypal Nature

JavaScript沒有classes的概念,對象都是直接繼承自其餘對象,即prototypal inheritance!

在JS有幾種繼承模式的類型:

  1. Classical
  2. Pseudoclassical
  3. Functional

ES6,引用了class,但本質未變,只是寫法上更方便。使用了new , class, extends關鍵字。

具體見以前博客:https://www.cnblogs.com/chentianwei/p/10197813.html

 

傳統的是函數繼承模式:

//函數user
let user = function(ops) {
  return {
    firstName: ops.firstName || 'John', 
    lastName: ops.lastName || 'Doe', 
    email: ops.email || 'test@test.com', 
    name: function() { return this.firstName + this.lastName}  
  }  
}

//繼承函數user,
let agency = function(ops) {
  ops = ops || {}
  var agency = user(ops)
  agency.customers = ops.customers || 0
  agency.isAegncy = true
  return agency
}

  

Node.js Globals and Reserved Keywords

  • process
  • global
  • module.exports, exports

Node.js Process Information

每一個Node.js script的運行,都是一個系統進程。

可使用process對象獲得,當前進程的相關信息:

process.pid

process.cwd()

node -e "console.log(process.pid)"

 

global Scope in Node.js

瀏覽器中的window, document對象都不存在於Node.js.

global是全局對象,可使用大量方法。如console, setTimeout(), global.process, global.require(), global.module

例子: global.module

Module {
  id: '<repl>', exports: {},
  parent: undefined,
  filename: null,
  loaded: false,
  children: [],
  paths:
   [ '/Users/chentianwei/repl/node_modules',
     '/Users/chentianwei/node_modules',
     '/Users/node_modules',
     '/node_modules',
     '/Users/chentianwei/.node_modules',
     '/Users/chentianwei/.node_libraries',
     '/Users/chentianwei/.nvm/versions/node/v11.0.0/lib/node' ] }

 

process對象有一系列的有用的信息和方法:

//退出當前進程,若是是在node環境編輯器,直接退出回到終端目錄:
process.exit()

⚠️在node環境,直接輸入process,獲得process對象的全部方法和信息。

 

Exporting and Importing Modules

module.exports = (app) => {
  //
  return app
}
const messages = require('./routes/messages.js')

真實案例使用:

const messages = require(path.join(__dirname, 'routes', 'messages.js'))

解釋:

_dirname得到絕對路徑, 在加上routes/message.js,獲得真實的路徑。

 

Node.js Core Modules

核心/基本模塊

Node.js不是一個沉重的標準庫。核心模塊很小,但足夠創建任何網絡應用。

Networking is at the core of Node.js!

主要但不是所有的core modules, classes, methods, and events include the following:

 

方便的Node.js Utilities


 

使用npm安裝Node.js的Modules

留意咱們須要package.json, node_modules文件夾來在本地安裝modules:

$ npm install <name>

例子:

npm install superagent

//而後在program.js,引進這個模塊。
const superagent = require('superagent')

  

使用npm的一大優點,全部依賴都是本地的

好比:

module A 使用modules B v1.3,

module C 使用modules B v2.0

A,C有它們各自的B的版本的本地拷貝。

這種策略比Ruby和其餘一些默認使用全局安裝的平臺更好。

 

最好不要把node_modules文件夾放入Git repository,當這個程序是一個模塊會被其餘app使用的話。

固然,推薦把node_modules放入會部署的app中,這樣能夠防備因爲依賴更新致使的意外損害。

 

Taming Callbacks in Node.js

callbacks讓node.js異步。使用promise, event emitters,或者async library能夠防止callback hell

 

Hello World Server with HTTP Node.js Module

Node.js主要用於創建networking app包括web apps。

由於自然的異步和內建的模塊(net, http),Node.js在networks方面快速發展。

下面是一個例子:

建立一個server object, 定義請求handler, 傳遞數據回到recipient,而後開啓server.js。

const http = require('http')
const port = 3000
const server = http.createServer((req, res) => {
  res.writeHead(200, {'Content-Type': 'text/plain'})
  res.end('Hello World\n')
}).listen(port, () => {
  console.log(`Server running at http://localhost:${port}`)
})

 

首先,須要用http module。並設置服務port.

而後,建立一個server, 它有一個回調函數,函數包括response的處理代碼。

爲了設置right header和status code:

  res.writeHead(200, {'Content-Type': 'text/plain'})

 

再輸出一個字符串,使用end symbol.

req和res參數是關於一個HTTP request和response data的信息。另外這2個參數可使用stream(這是一個模塊)

再而後,爲了讓server接受請求requests,使用listen()方法

最後,再terminal輸入:

node server.js

 

terminals上顯示console.log的信息:

Server running at http://localhost:3000
//在瀏覽器打開鏈接,可看到'Hello World'字樣。這是res.end()實現的。

 

 


 

 

Debugging Node.js Programs

現代軟件開發者,可使用如Chrome Developer Tools, Firfox Firebug。

由於Node.js和瀏覽器 JavaScript環境相似,因此咱們可使用大量豐富的Debug工具:

  • Core Node.js Debugge(非用於交互界面)
  • Node Inspector: Port of Google Chrome Developer Tools ✅推薦✅。
  • IDEs: WebStorm, VS Code and other IDEs

Core Node.js Debugger

最好的debugger是 console.log(), 😄。由於它不會打斷interrupt the flow。

首先,把debugger關鍵字,放在代碼內。

而後,使用開啓一個js文件的檢查:

 node inspect program.js

 

使用:

  • nextn: step to the next statement
  • contc: continue until the next debugger/break point

更多的見the official web site(http://nodejs.org/api/debugger.html).

非GUI,不直觀。

 

Debugging with node inspector

備註(原書提供的node-inspector安裝不上,打開其git,提示我看這篇文章:

Debugging Node.js with Chrome DevTools

使用chrome自帶的EevTools便可。

用法:

  1. node版本必須大於6.3
  2. 運行代碼:node --inspect hello.js(或者node --inspect-brk hello.js)
  3. 以後在瀏覽器地址欄輸入:  chrome//inspect
  4. 進入一個界面,點擊「Open dedicated DevTools for Node」連接。
  5. 會自帶打開一個新窗口,能夠在這裏debug。
    • 當你在terminal退出debug後,這個瀏覽器窗口會保留,當你再次dubug後,它會自動連接。

全部的chrome devtool功能均可以使用。

 

node官方的debug文檔:

https://nodejs.org/en/docs/guides/debugging-getting-started/

 

缺點是:沒法在原文件上斷點。dubugger!

 

Visual Studio Code (https://code.visualstudio.com/nodejs

被推薦的一個免費的跨平臺的Node.js編輯器,包括內建terminal, Node.js debugging。和大量擴展功能。

被高度推薦:使用方法見(廖雪峯)

 

atom能夠在原文件斷點可是功能弱,可使用chrome代替。


 

 

Watching for File Changes

Node.js程序儲存在內存,若是改變source code, 咱們須要重啓進程process(i.e., node).

手動killing 進程並重開啓一個新的. (Control + C on mac)

⚠️提示:使用Express.js,它會自動reload模版文件,爲每次的新請求。因此server無需重啓。


 


 

 

第二章 使用框架來建立Node.js Web Apps

(摘錄)

Node.js相比Ruby或Java是一個比較年輕的平臺。Express是很流行的框架之一。

  • What Express.js is
  • How Express.js works
  • Express.js Installation
  • Express.js scaffolding (command-line tool)
  • The Blog Project overview
  • Express.js Hello World example

Express是web框架,基於core Node.js http和  Connect (http://www.senchalabs.org/connect) 組件。

組件被稱爲中間件middleware。它們是框架哲學的基石,配置大於約定。

所以,Express是高度配置的,在開發階段是靈活的和高度客制的。

若是你寫node web apps, 只使用core Node.js modules,你會發現你反覆的一遍遍的造輪子:

  • Parsing of HTTP request bodies
  • Parsing of cookies
  • Getting information from URL
  • Reading query string from URLs or request bodies
  • 管理web sessions
  • 組織routes和a chain of if 條件,基於URL paths和HTTP methods of the request.
  • 根據data types, 決定適當的響應頭
  • ...

Express.js提供了MVC-like的結構爲你的web apps。

models可使用 Mongoose (http://mongoosejs.com) or Sequelize (http://sequelizejs.com) libraries 。

 

Express.js相似Ruby on Rails. 區別是rails是約定大於配置。

雖然Express是最流行的框架,但仍有不一樣特點的新框架出現,如Meteor。 

 


 

How Express.js Works

一個主文件,通常叫server.js, app.js, index.js。

通常這個文件是node命令的開始, 或者做爲模塊export這個文件 。

在這個文件內,咱們作:

  1. 包括第三方依賴做爲modules, 例如controllers, utilities, helpers, models。
  2. 配置app設置,如template engine, 和它的文件擴展。
  3. 鏈接數據庫,如MongoDB, Redis, MySQL
  4. 定義middleware,如error handlers, static file folder, cookies, 其餘parsers.
  5. 定義routes
  6. 開始app
  7. Export這個app 做爲modules

當Express.js app運行,它監聽請求。每一個進來的請求經過一個定義的中間件鏈條和路徑被處理processed。

經過execution flow進行控制。


 

 

安裝

建立Express.js app使用,2種方法:

1. express-generator:一個全局的npm包,提供命令行工具來快速的建立程序手腳架--推薦快速的prototyping和服務端(thick server)渲染程序。

2. express:  一個本地的包模塊在Node.js app's的node_modules文件夾內--推薦任何程序,須要import express(使用require()或import)

 

看看當前版本,而後安裝:

npm view express
npm i -g express-generator@latest
express --version

 

注意⚠️mac用戶,可能須要安裝權限。使用sudo。


 

Local Express.js 在本地安裝Express.js

創建一個文件夾,進入,而後建立package.json,

npm init

 

而後安裝一個版本:

$ npm install express@4.15.4  --exact
{
  "name": "hello-simple",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.15.4"
  }
}

 

package-lock.json ,用於鎖定版本。

若是想要改變版本:

npm install express@4.15.5 --save

 

Create a server.js file

const express = require('express')
let app = express()

app.all('*', (req, res) => {
  res.send('Welcome to Practical node.js!')
})

app.listen(3000, () => {
  return console.log('Open at localhost:3000')
})

Then launch it with node server.js to see "Welcome to Practical Node.js!" in a browser at http://localhost:3000

 


 

Express.js Scaffolding  建立express.js的手腳架

Comparable with Ruby on Rails and many other web frameworks, Express.js comes with a CLI for jump-starting your development process

幫助命令:

$ express -h
//運行一個terminal命令,建立手腳架
express [options] [dir|appname]

下面的步驟:

  1. 檢查版本
  2. 執行scaffolding command with options
  3. run app locally
  4. 理解sections, routes, middleware, configuration
  5. 看一下Pug模版。(詳細看Chapter3)

 

Express.js Command-Line Interface

$ express -c styl express-styl
//根據terminal上的提示:輸入下面的代碼,進入文件夾並安裝相關依賴。
$ cd express-styl && npm install
//運行app $ DEBUG=express-styl:* npm start

建立了一個app,👍!

進入express-styl/app.js:

const express = require('express');
const path = require('path');
const favicon = require('serve-favicon');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const stylus = require('stylus');

const index = require('./routes/index');
const users = require('./routes/users');

let app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(stylus.middleware(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', index);
app.use('/users', users);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

server文件有routes, 來自routes文件夾。

Express app 被輸出:module.exports

被髮射伴隨listen(),在bin/www文件內。

下面看一下app.js內的代碼:

 

Routes in Express.js

能夠在express-styl/app.js內看到自動生成的2個routes:

 
 

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

//...

app.use('/', indexRouter);
app.use('/users', usersRouter);

第一行app.use():處理全部到home page的請求。如:http://localhost:3000/

第二行app.use():處理到/users,如http://localhost:3000/users.

2個routes處理URLs是大小寫字母敏感的。

 

默認, Express.js不容許開發者經過query string arguments 來導航routes 

GET: www.webapplog.com/books/?id=10&ref=201

 

而是,使用middleware:

app.use((req, res, next) => {
  next()
})

// next是一個回調函數。

 

開發者也能夠完成response, 經過使用send(), end(), render()或其餘Express method,

或者傳遞一個❌對象給next()來回調!

app.use((req, res, next) => {
  if (!req.session.loggedIN) { 
    return next(new Error('Not enough permissions'))
  }
  if (req.session.credits === 0) {
    return res.render('not-enough-credits.pug')
  }
 next()
})

 

下面是另外一個例子:

用條件邏輯來處理一個查詢string, 使用req.query對象:

app.use((req, res, next) => {
  if (req.query.id) {
    //處理id,而後當完成後,調用next()
  } else if (req.query.author) {
    //和id相同的方式approach
  } else if (req.query.id && req.query.ref) {
    //當id and ref存在時,處理。
  } else {
    next()
  }
})

app.get('/about', (req, res, next) => {
  //這裏的代碼,在query string middleware以後執行。
})

 

 

一個重要的特色:

只要request同樣,每一個req或者res對象在隨後的中間件函數或者request handler functions內,req或res對象仍是這個req or res對象。

req對象->中間件1函數->中間件2函數->請求處理函數->...->req對象(內部的key/value發生了變化)

 

這個特色,讓開發者能夠decorate a reference or a value。例如:

讓第一個中間件的req對象獲得數據庫傳入的數據,隨後的第2箇中間件中的req對象,就是第一個中間件執行完代碼後的req對象, 這個req對象包含數據庫數據。

(個人我的理解:相似Promise.then()鏈條傳遞的promise對象.)

app.use((req, res, next) => {
  req.db = const db = mongoskin.db('mongodb://@localhost:27017/test')
})
//在上一個中間件執行後,req對象新增了db屬性。這個req對象被傳入下一個中間件
app.use((req, res, next) => {
  req.articles =  req.db.collection('articles')
})
//上箇中間件執行完成後,req對象又新增了articles屬性。這個req對象被傳入下一個中間件:
app.post('/users', (req, res, next) => { 
// use req.db or req.articles req.db.collection('users').insert({}, {}, (error, results)=>{ req.articles.insert({}, {}, (error, results)=>{ res.send() }) }) })

 

 

回到app.js 文件。對root請求處理, 是"/",至關於routes/index.js。

來自HTTP request 的Everything 都在req對象內,而且把結果寫入res對象。

在express-styl/routes文件夾,分別存在index.js和users.js,這2個文件導出後,會被app.js引入並使用。

var express = require('express')
var router = express.Router()

// 獲得home , res對象使用render()方法。
router.get('/', function(req,res, next) {
  res.render('index', {title: 'Express'})
})
module.exports = router
//users.js
var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/', function(req, res, next) {
  res.send('respond with a resource');
});

module.exports = router;

 

 

Middleware as the Backbone

中間件是Express.js框架的支柱,脊樑骨。

在express-styl/app.js,每行/每一個聲明在routes上面,都是中間件。

這個中間件包括pass-through functions。當請求在中間件內旅行時,中間件會對請求request作有用或有幫助的事情。

const express = require('express');
const path = require('path');
const favicon = require('serve-favicon');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const stylus = require('stylus');
//...
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

 

例如:

bodyParser(), cookieParser() add HTTP request payload (req.body) 並 parsed cookie data(req.cookie)

app.use(logger('dev')),在terminal上打印每個請求。

在Express v3, 這些中間件是內建的module。

在v4之後,Express Generator 聲明和包含了app.js 和 package.json, 咱們使用npm install來增長鬚要的modules。如:static-faviconmorgancookie-parser and body-parser.


 

Configuring an Express.js App

 這是咱們在一個典型的Express.js中的app.js內,定義配置聲明。使用app.set()

 第一個參數是名字,第二個參數是值。

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

在bin/www文件內:

 * Module dependencies.
var app = require('../app');
var debug = require('debug')('express-styl:server');
var http = require('http');

 

//Get port from environment and store in Express.
//定義port變量,並賦值。當server啓動後,會被用到。
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

 

建立http server
var
server = http.createServer(app);

 

//監聽提供的端口,並當error和listening事件,發生時執行onError, onListening回調函數。
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

 

onError和onListening回調函數,定義在這個www文件內。

 


 

Pug Is Haml for Express.js/Node.js

Pug是一個模版引擎。相似Ruby on Rails的Haml。它使用whitespace和縮排列。

doctype html
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/style.css')
  body
    block content

第4章會講解它。(相似RoR的slim)可用可不用,每感受效率提升多少,看開發團隊是否用。


 

 

The Blog Project Overview

建立一個簡單的blog頁面,及相關功能。

  • home page, 一些文章
  • 獨立的文章頁面,全文顯示一篇文章
  • 管理員頁面,發佈或移除。
  • 登錄頁面,進入管理員頁面。
  • post 頁面,用於新增文章。

從一個開發者的視角,app有如下元素:

  • app.js主文件: Settings, routes, 其餘重要的路徑。 這個文件和node運行來開始server。
  • Routes: 全部的涉及頁面的邏輯。如從數據庫取數據,編譯這些數據到HTML。
  • Node.js 文件package.json: 依賴和其餘元數據。
  • 在mode_modules內的依賴: 第三方modules,(經過package.json安裝的)
  • Database: 一個MongoDB實例,和一些seed data.
  • Templates: *.pug文件。
  • Static files: 如*.css,或者browser *.js
  • Configuration 文件config.json:安全設置,其餘程序設置,如app的title.

這個程序包括全部的CRUD元素。另外使用兩個方法發數據到server:

  1. 經過傳統的form, 徹底刷新頁面。
  2. 經過REST API(AJAX HTTP request) 

第一種是現代開發網頁棄用的方式,速度太慢。

第2種是發送和接收數據,經過REST API/HTTP request和渲染客戶端HTML。這些行爲使用前端框架,例如React, Angular, Vue.js等等( many others (http://todomvc.com))。這些框架十分流行。

 

在hood罩子下面,事實上全部前端都使用jQuery's ajax()方法。

爲了演示,本例子使用REST API經過$.ajax()。

同時,這個例子不使用CLI手腳架。逐步演示代碼。若是建立一個Express.js。讓你理解在這個框架下代碼是如何組織在一塊兒工做的。

開始把,建立咱們的程序文件夾。

 

Express.js Hello World Example

一個例子,不使用generators, 額外的modules和middleware。包括如下部分:

  • 創建folders
  • npm init and package.json
  • Dependecy declaration
  • app.js 文件
  • Meet Pug
  • Running the app

 

第一步Setting Up Folders

Express.js是高度配置的,全部文件夾均可以重命名。不過,默認的文件夾不要更名:

  • node_modules:第三方 modules的代碼放在這裏。包括Express.js和Connect libraries。
  • views: 模版引擎文件Pug或其餘。

這就夠了。若是想要爲以後的章節的其餘案例建立新的文件夾,可建立:

  • routes: Node.js modules包括請求處理
  • db: 發送數據和scripts ,使用MongoDB
  • public: 全部靜態的文件。包括HTML,CSS,JavaScript(browser), Stylus(或者其餘的CSS語言框架文件)

建立文件夾hello-world

mkdir hello-world
cd hello-world
mkdir {public,public/css,public/img,public/js,db,views,views/includes,routes}

 

 

第二步npm init and package.json 

上一步,沒有使用Express.js Generator。

npm不只是一個註冊器,也是一個依賴管理工具。它永久創建程序文件package.json。

npm init   //建立package.json

 

$ npm install express //安裝最新的穩定版本。

 

⚠️推薦使用明確的指定版本,使用@符號。

npm install express@4.15.4 --save

 

再安裝

  • Pug: 2.0.0-rc.4
  • Stylus: 0.54.5

第三步Dependency Declaration: npm install

另外一個建立package.json文件的方法是拷貝粘貼代碼到package.json, 而後運行npm install

對腳本進行修改:如⬇️所見:

{{
  "name": "hello-advanced",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "4.15.4",
    "pug": "2.0.0-rc.4"
  }
}

 

main entry point,即設定一個主文件main file: 

通常使用app.js或者index.js, 執行這個腳本文件使用如下隨意的一個:

$ node app.js
$ node app
$ npm start   

//由於在package.json內設定了"scripts": { "start": "node app.js"}

 下一步,讓咱們建立app.js

 

第四步The App.js File

主文件的結構基本內容包括:

  1. Require dependencies
  2. Configure settings
  3. Connect to database(可選)
  4. Define middleware
  5. Define routes
  6. Start the server on a particular port
  7. Start workers with clusters to scale (a term spawn workers is also used for this) (optional)

1到7的順序很重要,由於請求從上到下的通過中間件的鏈條。


打開app.js,而後:

//引入模塊。
// path module 用於處理文件和目錄的路徑。
const express = require('express')
const http = require('http')
const path = require('path')
// Express使用一個函數模式,執行函數,獲得一個實例。
let app = express();
// 使用express實例方法set('name', 'value')來進行配置
app.set('appName', 'hello-advanced')

 

還須要定義一些配置在app.js:

  • port: 端口,是一個number, server會監聽請求。
  • views:template文件的絕對路徑。
  • view engine:  模版文件的擴展(html, pug)

若是想要使用環境變量提供的port number,使用模塊process的方法:

process.env.PORT

代碼以下:

app.set('port', process.env.PORT || 3000)
app.set('views', path.join(_dirname, 'views'))
app.set('view engine', 'html')

 

 

__dirname

 is an absolute path to the folder with the source code script (a file in which the global variable is called). 獲得程序代碼所在的文件夾。

本application是"/Users/chen/node_practice/hello-world"

//如何查詢
node inspect app.js
//而後在控制檯輸入__dirname,便可返回路徑

 

path.join([...paths])是path模塊的方法之一

// ..返回上一個文件夾
path.join('/foo', 'bar', 'baz/asdf', 'quux', '..');
// Returns: '/foo/bar/baz/asdf'

 

 

而後,進入中間件 部分。

中間件是Express.js框架的backbone。

它包括:

  • 在第三方模塊內的定義。例如:app.use(bodyParser.join());  這是body-parser模塊的方法。
  • 在app或它的模塊內的定義。 例如:app.use(function(req, res, next) { ... })

Middleware用於組織和複用代碼,本質就是帶參數的函數。(第6章會作更多的講解)

 

routes

下一個組件是routes。Routes處理requests。定義路徑使用幫助方法app.VERB(url, fn1, fn2, ...)

fn:request handlers

url:是URL pattern in RegExp

VERB:是get , post, put, patch, del, all, 用於捕捉不一樣的請求。

Routes按它們被定義的順序,被處理。通常routes被放在middleware後面,可是一些中間件放在routes後面。例如error handler。

下圖展現一個請求的旅行:

 

在本app Hello World, 只使用一個route,來獲得全部關於URLs的方法的請求(*通配符號wildcard百搭牌)

app.all('*', (req, res) => {
  res.render('index', {msg: 'Welcome to Practical Note.js!'})
})

 

在這個請求內,使用res.render()函數渲染視圖模版。res.render()的第一個參數是名字'index', 第二個參數是數據對象data object。

 

res.render(viewName, data, callback(error, html))

 express的方法。

  • viewName: 模版名字及擴展名(file extension)
  • data: 一個可選的對象被傳入,(從數據庫取出的數據)
  • callback: 一個可選的函數被調用,用於處理an error and HTML當compilation is complete。

render()方法調用後,調用core http組件的end()方法,用於完成response。

換言之,中間件的鏈條不會在res.render()後繼續執行代碼。

(第4章,詳細分析)

 

最後但不是最少的是開啓服務的說明。在以前的章節的Hello World app, 你看到app.listen(),

可是http.createServer(app).listen()也能夠生效。這2個鏈接的方法都是核心模塊http的方法。

server.listen() 

監聽鏈接。

http.createServer(app).listen(app.get('port'), () => {
  console.log(`Express server listening on port ${app.get('port')}`)
})

 

你也可使用https.createServer(app).listen() for the HTTPS support, 當你準備好部署你的server到產品。

在運行server以前,咱們須要建立views/index.html文件 

 

建立index視圖文件

Express默認使用jade模版,也能夠自定義如Pug,

若是想使用原生html模版須要安裝ejs (點擊查看原文解釋)

npm install ejs

//引入ejs
var ejs = require('ejs')

//設置html engine
app.engine('html', ejs.__express)

//設置視圖引擎, 'view engine'表示沒有指定文件模版格式時,默認使用的引擎插件。
app.set('view engine', 'html')

:在express搭建的服務器中,html引擎沒有被配置,直接添加便可;視圖引擎已配置,修改配置便可。

index.html內的代碼:

<h1>hello</h1>
<p>You are welcome</p>

// 插入傳入模版的數據。
<p><%= msg %></p>

 

app.engine(ext, callback)

http://expressjs.com/en/4x/api.html#app.engine

Registers the given template engine callback as ext.

默認,Express將require()這個基於文件擴展的engine。 

app.engine('pug', require('pug').__express);
app.engine('html', require('ejs').renderFile); //也能夠用__express方法

 

 

Running the Hello World App

$ node app 

打開http://localhost:3000.

 

總結:

第2章,學習使用Express.js, 知道它是如何工做的。瞭解使用手腳架來生成apps。

經過Blog app案例,瞭解了建立這個程序的過程。

最後,咱們接觸了一些主題:settings, request process, routes, Ajax server side, ejs模塊產生模版。

 

下一章,談談驅動測試開發。另外會增長一個數據庫到Blog routes。展現如何把數據轉入到HTML pages!

相關文章
相關標籤/搜索