iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 18
1
Modern Web

還在想要買哪一堂線上課程嗎?培養看文件的習慣吧!用 MDN 文件學後端:NodeJS & MongooseDB系列 第 18

18日: Express/Node introduction ( 非同步 APIs 、 建立 route handlers 、 使用 middleware )

  • 分享至 

  • xImage
  •  

承上篇 出處 , 有簡體版 , 進入後自行點選

寫在前面

大部分 MDN 文件都有簡中版 , 感謝網友 杯(附上他的鐵人文目錄,也有提到Node, Express, MongooseDB) 提供

Using asynchronous APIs

使用非同步 APIs 。 JS 使用非同步 APIs 的頻率高過於同步 , 用於執行一些要等某些行為先完成再開始動作的任務 。 同步 API 是一個一個操作完畢後 , 才會開始執行下一個 , 例如下面這段 log function 是同步的 , 它們會從上到下依序印出 'First, Second'

console.log('First');
console.log('Second');

非同步則是立即執行回傳 , 上一動還沒完畢就可以執行 。 一旦操作結束 , API 會使用某個機制來進行額外的操作 。 例如下方 code 會印出 'Second, First' , 原因是就算 setTimeout() 在第一行 , 它執行結束前第四行的 console.log() 就已經執行結束

setTimeout(function() {
  console.log('First');
  }, 3000);
console.log('Second');

在 Node 中使用不阻擋非同步APIs ( non-blocking asynchronous APIs ) 非常重要 , 比在瀏覽器中用還更重要 ! 因為 Node 是單線事件導向 ( single-treaded event-driven ) 的執行環境 。
Single threaded 是指所有要傳到 server 的 req 同時跑在同一條線上 ( 與之相對則是多產線處理 ) , 這個模式相當有效率 , 但它同時代表如果你的函式呼叫需要長時間完成的同步 methods , 它不只塞住現在的 req , 還有每一個 web app 正在處理的 req

有很多方式可以通知 app 非同步 API 已經跑完了 , 最常見的是當你使用非同步 API 時 , 註冊 ( register ) 一個 callback function , 這會在非同步跑完的時候被觸發 。 這也是上面那段 code 使用的方法

Tip: 如果我們有一連串相依非同步又需要依序的運作 , 用 callback 會變得很雜亂 , 因為這會導致過度巢狀 , 這個問題被稱作 callback hell
可以用 async module , 或 ES6Promises 解決這問題
Note: Express & Node 有個慣例是用錯誤優先處理的 callbacks ( 參考資料: 你懂 JavaScript 嗎?#23 Callback 出處: Summer。桑莫。夏天 ) , 這個慣例中 , 第一個函式的值是錯的 , 後續的參數包含正確的資料 。
這個部落格解釋為什麼這個方法很有用 : The Node.js Way - Understanding Error-First Callbacks (fredkschott.com)

Creating route handlers

Hello World 範例 ( 在昨天的文 ) 裡我們定義一個 callback route handler function 解決 HTTP GET req 指向網站根目錄 ('/')

app.get('/', function(req, res) {
  res.send('Hello World!');
});

Number of other res methods , 例如 : res.json() or res.sendFile()

JS tip: 可以任意命名參數 , 第一個參數會被當作 req , 第二個當作 res , 習慣上直接如範例命名 , 有利於我們進行辨識

Express app 物件提供定義 route handlers 的方法 , 大部分的用法都很相似 :
delete(), get(), post(), put(),

checkout(), copy(), head(), lock(), merge(), mkactivity(), mkcol(), move(), m-search(), notify(), options(), patch(), purge(), report(), search(), subscribe(), trace(), unlock(), unsubscribe().

有一個很特殊的 method app.all() , 在 res 給任何 HTTP method 時會被觸發 。
這被用在指定路徑讀取 middleware functions 時 , Express 文件裡的一個範例 : req to /secret 且無論是用哪個 HTTP verb ( 前提是要 http module 有支援 )

app.all('/secret', function(req, res, next) {
  console.log('Accessing the secret section ...');
  next(); // pass control to the next handler
});

路由允許 URL patterns 、 從 URL 傳遞的參數值交由 handler 。

為網站特定部分把 route handlers 一起控管 , 然後用一個常見的前綴路由 ( route-prefix , 例如 Wiki 可能把所有相關路由放在一個檔案 , 用的 prefix 是 /wiki/ ) , 這樣做會很有幫助 。
在 Express 中 , 我們使用 express.Router object , 例如 : 可以建立一個我們自己的 wiki route module ( 放在 wiki.js ) , 然後將她 export 。 如下

// wiki.js - Wiki route module

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

// Home page route
router.get('/', function(req, res) {
  res.send('Wiki home page');
});

// About page route
router.get('/about', function(req, res) {
  res.send('About this wiki');
});

module.exports = router;

Note: 在 Router obj 新增 routes 就像加在 app obj 裡面一樣 ( 應該是呼應昨天的文 )

要在我們的 Express app 檔案裡面用剛剛設定的路由 , 要進行 require() route module ( wiki.js ) , 然後呼叫 use() 去新增 middleware handling path Router , 以下兩個 routes 就可以被取用 : /wiki/ & /wiki/about

var wiki = require('./wiki.js');
// ...
app.use('/wiki', wiki);

後續將會有更多 routes 的內容 , 還有 Router 用法 。 先上連結: Routes and controllers


上一篇
17日: Express/Node introduction ( Node & Express 從何而生 、 有多熱門 、 主導性 、 Importing and creating modules )
下一篇
19日: Express/Node introduction ( 使用 middleware 、 Serving 靜態檔案 )
系列文
還在想要買哪一堂線上課程嗎?培養看文件的習慣吧!用 MDN 文件學後端:NodeJS & MongooseDB30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言