成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Node.js 系列:原生 Node.js 應(yīng)用

Ocean / 1238人閱讀

摘要:原生應(yīng)用是一個基于引擎的運(yùn)行環(huán)境使用了一個事件驅(qū)動非阻塞式的模型,使其輕量又高效的包管理器,是全球最大的開源庫生態(tài)系統(tǒng)本文主要介紹構(gòu)建一個應(yīng)用的基本步驟和模塊,并假定你已經(jīng)對有一定的了解本文引用部分代碼作為例子,如果希望參看全部源碼,歡迎去

原生 Node.js 應(yīng)用
Node.js 是一個基于 Chrome V8 引擎的 JavaScript 運(yùn)行環(huán)境
Node.js 使用了一個事件驅(qū)動、非阻塞式 I/O 的模型,使其輕量又高效
Node.js 的包管理器 npm,是全球最大的開源庫生態(tài)系統(tǒng)

? 本文主要介紹構(gòu)建一個 Node.js 應(yīng)用的基本步驟和模塊,并假定你已經(jīng)對 Node.js Api 有一定的了解

? 本文引用部分代碼作為例子,如果希望參看全部源碼,歡迎去 github 查閱(如果覺得有一定幫助,歡迎star)

模塊架構(gòu)設(shè)計(jì)

整個 Node.js 應(yīng)用的架構(gòu)設(shè)計(jì)

node.js 應(yīng)用構(gòu)成

引入模塊:通過 require 指令來引入 Node.js 模塊

創(chuàng)建服務(wù)器:服務(wù)器用來監(jiān)聽客戶端請求

接收請求和響應(yīng)請求:接收客戶端的HTTP請求,返回響應(yīng)數(shù)據(jù)

// 通過 require 引入 http 模塊,并將實(shí)例化的 HTTP 賦值給 http 變量
const http = require("http");
// 引入 url 模塊,用來解析數(shù)據(jù)
const url = require("url");

function ylone(router, handleObj) {
    const hostname = "127.0.0.1";
    const port = 7777;
    // http.createServer(function(){}) 方法創(chuàng)建服務(wù)器,并返回一個對象
    const server = http.createServer((req, res) => {
        const path = url.parse(req.url);
        const pathName = path.pathname;
        // 處理node.js每次自動請求favicon.ico
        if (pathName !== "/favicon.ico") {
          const content = router(handleObj, pathName, res, req);
        }
    });

    // server.listen() 方法綁定主機(jī)和端口
    server.listen(port, hostname, () => {
        console.log(`服務(wù)運(yùn)行在${hostname}:${port}`);
    });
}

exports.ylone = ylone;
基于事件驅(qū)動的回調(diào)

http.createServer((req, res) => {...}) 是一個典型的回調(diào),事實(shí)上,這就是 Node.js 原生的工作方式

這里直接將一個匿名函數(shù)作為變量進(jìn)行傳遞,繞開了“先定義,再傳遞”的圈子

像寫 PHP 應(yīng)用時:任何時候當(dāng)有請求進(jìn)入時,服務(wù)器(如Apache)就會為這個請求創(chuàng)建一個新的進(jìn)程,并且從頭至尾執(zhí)行相應(yīng)的 PHP 腳本

在 Node.js 中,無論何時當(dāng)一個新的請求到達(dá)指定端口時,我們在服務(wù)器創(chuàng)建時傳遞的函數(shù)就會被調(diào)用

Node.js 模塊

模塊意味著將 Node.js 應(yīng)用(如 http.js)抽象成一個模塊,通過入口文件 index.js 去調(diào)用相應(yīng)的模塊來引導(dǎo)和啟動應(yīng)用

將代碼模塊化意味著我們將提供其功能的部分(如 一個函數(shù))導(dǎo)出到請求這個模塊的腳本內(nèi)

const server = require("./http");
const router = require("./route");
const handle = require("./requestHandle");

var handleObj = {};
// 入口 Case
handleObj["/"] = handle.hello;
// 非阻塞 Case
handleObj["/vlone"] = handle.vlone;
// post Case
handleObj["/supreme"] = handle.supreme;
// get Case
handleObj["/adidas"] = handle.adidas;

server.ylone(router.router, handleObj);
路由

為了處理不同的 http 請求,我們需要通過創(chuàng)建一個路由模塊來進(jìn)行“路由選擇”

為路由提供請求的 url 和其他需要的 get 和 post 參數(shù),隨后路由根據(jù)這些數(shù)據(jù)來執(zhí)行相應(yīng)的代碼

我們所需要的數(shù)據(jù)都在 http.createServer((req, res) => {...}) 的 req 參數(shù)中,為了解析 req,需要額外引入 urlquerystring Node.js 模塊

在 index.js 內(nèi)引入路由對象,將路由方法傳遞給 http 應(yīng)用,在 http.createServer((req, res) => {...}) 內(nèi)解析 req 參數(shù),然后調(diào)用 router 方法

理解以下函數(shù)式編程:將 router 對象傳遞給 index,在 index 內(nèi)將 router 方法傳遞給 http,因?yàn)?http 并不關(guān)心 router 方法從哪來,只需要執(zhí)行方法,然后完成業(yè)務(wù),但是首先需要保證有這個對象

函數(shù)式編程最基本,最核心的即思想轉(zhuǎn)換,由名詞到動詞,由對象到方法,行為驅(qū)動執(zhí)行

function router(handleObj, pathName, res, req) {
  if (typeof handleObj[pathName] === "function") {
    return handleObj[pathName](res, req);
  } else {
    res.writeHead(200, {
          "Content-type": "text/plain"
    });
    const content = "404 Not Found";
    res.write(content);
    res.end();
  }
}

exports.router = router;
將路由分發(fā)到請求處理函數(shù)

需要創(chuàng)建一個新的 resquestHandlers 模塊,封裝各個處理函數(shù)來對應(yīng)不同的請求

在 JavaScript 中通過對象鍵值對來封裝 路徑->方法 的映射關(guān)系

在 C++ 或者 C# 中,對象指的是類或者結(jié)構(gòu)體的實(shí)例,對象根據(jù)其實(shí)例化的模板會擁有不同的屬性和方法

在 JavaScript 中,對象是一個鍵值對集合

在入口文件(index.js)內(nèi)引入 requestHandle,同時聲明一個操作對象(handleObj),用來存儲 路徑->方法 的映射關(guān)系,最后將路由方法和操作對象傳遞給服務(wù)器應(yīng)用(http.js)

在服務(wù)器應(yīng)用內(nèi),獲得瀏覽器請求的路徑,調(diào)用路由方法(router),將操作對象(handleObj)和請求路徑作為參數(shù)傳遞

在路由內(nèi)(route.js)獲取路徑對應(yīng)的函數(shù),自執(zhí)行函數(shù)

因?yàn)槲恼缕?,這里只展示關(guān)鍵代碼,源碼參看 github

const { exec } = require("child_process");
const querystring = require("querystring");
const url = require("url");

function createHttp(type, res, val) {
    const content = val;
    const conType = {
        plain: "text/plain;charset=utf-8",
        html: "text/html",
    };
    // 為隱式的響應(yīng)頭設(shè)置值
    res.writeHead(200, {
        "Content-type": conType[type]
    });
    // 發(fā)送響應(yīng)主體
    res.write(content);
    // http 完成響應(yīng)
    res.end();
}

... something else

function vlone(res) {
    exec("node --version", (error, stdout, stderr) => {
        if (error) {
            console.log(error, stdout, stderr);
            return;
        }
        const content = stdout;
        const type = "plain";
        createHttp(type, res, content);
    });
}

... something else
阻塞與非阻塞

A() 方法讀取文件,因此需要一定的響應(yīng)時間,B() 方法代表其他需要執(zhí)行的代碼

阻塞:在A() 執(zhí)行的過程中,B() 處于等待狀態(tài),當(dāng)A() 訪問文件數(shù)據(jù)準(zhǔn)備就緒后,B() 才開始執(zhí)行

由上圖可以看出,應(yīng)用程序從進(jìn)行系統(tǒng)調(diào)用到復(fù)制數(shù)據(jù)報(bào)到應(yīng)用進(jìn)程緩沖區(qū)的整段過程是阻塞的,直到數(shù)據(jù)報(bào)被復(fù)制到用戶空間完成后,用戶進(jìn)程才解除阻塞狀態(tài),繼續(xù)執(zhí)行下一個應(yīng)用程序

優(yōu)點(diǎn):能夠及時返回?cái)?shù)據(jù),無延遲,方便調(diào)試

缺點(diǎn):需要等待

非阻塞:在A() 執(zhí)行的過程中,B() 同時執(zhí)行,且當(dāng)A() 訪問文件數(shù)據(jù)準(zhǔn)備就緒后,A() 會被執(zhí)行完成

由上圖可以看出,應(yīng)用程序在調(diào)用過程中,如果數(shù)據(jù)報(bào)還沒有準(zhǔn)備就緒,會先返回一個錯誤信息(EWOULDBLOCK),此時當(dāng)前進(jìn)程可以執(zhí)行其他方法,而不會阻塞。而 A() 會輪詢內(nèi)核,返回緩沖區(qū)數(shù)據(jù)是否準(zhǔn)備就緒

優(yōu)點(diǎn):不需要等待,當(dāng)前線程可以處理多個任務(wù)

缺點(diǎn):增大了任務(wù)完成的響應(yīng)延遲,因?yàn)槿蝿?wù)可能在兩次輪詢間隔內(nèi)完成,從而導(dǎo)致整體數(shù)據(jù)的吞吐量降低

以非阻塞方式進(jìn)行請求響應(yīng)

當(dāng)前的應(yīng)用交互方式:(請求處理程序 -> 請求路由 -> 服務(wù)器)將請求處理程序返回的內(nèi)容(請求處理程序最終要顯示給用戶的內(nèi)容)傳遞給HTTP服務(wù)器

當(dāng)前這種交互方式的問題在于,如果請求處理程序中有 Node.js 封裝的非阻塞方法A(),那么A() 在阻塞過程中,服務(wù)器就已經(jīng)將數(shù)據(jù)返回了,并不會等到A() 執(zhí)行完畢

為了解決上述問題,以非阻塞方式進(jìn)行請求響應(yīng),相對于之前將數(shù)據(jù)傳遞給服務(wù)器的方式,現(xiàn)在我們需要將服務(wù)器(response對象)傳遞給生成數(shù)據(jù)的應(yīng)用內(nèi),待數(shù)據(jù)準(zhǔn)備完畢,再返回響應(yīng)數(shù)據(jù)

這樣可以同時請求兩個路徑(實(shí)際上就是觸發(fā)兩個函數(shù)方法),B() 并不會因?yàn)锳()執(zhí)行時間長而處于等待狀態(tài)

處理 post 請求

創(chuàng)建一個表單元素,設(shè)置表單提交方法為 post, 每當(dāng)用戶提交表單時,則觸發(fā) supreme() 方法

處理 post 請求一般采用異步非阻塞方式,因?yàn)?post 請求一般會比較重,你無法控制用戶輸入的數(shù)據(jù)量,如果用阻塞的方式處理則必然會導(dǎo)致用戶操作阻塞

為了實(shí)現(xiàn)非阻塞,Node.js 會將 post 數(shù)據(jù)拆分成數(shù)據(jù)塊,然后通過出發(fā)特定事件,將這些數(shù)據(jù)塊傳遞給回調(diào)函數(shù)

常用的 post 兩個事件:data事件(新的數(shù)據(jù)塊到達(dá)時觸發(fā)),end事件(所有數(shù)據(jù)都已經(jīng)接收完畢時觸發(fā))

通過在 request 對象上注冊監(jiān)聽器(listener)來告訴應(yīng)用當(dāng) post 事件觸發(fā)時,應(yīng)該觸發(fā)哪些回調(diào)函數(shù)

處理 get 請求

通過 Node.js 封裝的 url對象來解析 url 參數(shù),獲取關(guān)鍵數(shù)據(jù)

url.parse() 的第二參數(shù) parseQueryString 如果為 true,則 query 屬性總是會通過 querystring 模塊的 parse() 方法生成一個對象

some pieces

當(dāng)寫好 Node.js 腳本(如 ylone.js)后,通過 node ylone.js 命令執(zhí)行腳本

在瀏覽器訪問指定地址(如 http://localhost:7777/)意味著向服務(wù)器發(fā)出請求,從而觸發(fā)服務(wù)器創(chuàng)建時的回調(diào)函數(shù)

當(dāng)訪問網(wǎng)頁(如 http://localhost:7777/)時,控制臺可能會輸出兩次 req 的數(shù)據(jù),那是因?yàn)榇蟛糠譃g覽器會在訪問網(wǎng)頁時嘗試讀取 favicon.ico 文件

針對瀏覽器每次發(fā)送請求,都會默認(rèn)請求一次 /favicon.ico 的問題,可以在 http 中對其進(jìn)行過濾,不執(zhí)行操作

如果希望在 Node.js 內(nèi)的傳遞一個 html 片段,并渲染在瀏覽器上,需要將 res.writeHead(200, {"Content-type": "text/plain"}) 的 Content-type 設(shè)置為 text/html

Node.js 返回?cái)?shù)據(jù)(response)在瀏覽器展示亂碼,通過在 res.writeHead(200, {"Content-type": "text/plain;charset=utf-8"}) 加上 charset=utf-8 配置解決

--Respect Node.js--

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/93914.html

相關(guān)文章

  • 前端每周清單第 12 期:支付寶前端構(gòu)建工具發(fā)展、LinkedIn用Brotli加快網(wǎng)頁響應(yīng)速度、餓

    摘要:前端每周清單第期支付寶前端構(gòu)建工具發(fā)展用加快網(wǎng)頁響應(yīng)速度餓了么升級實(shí)踐前端前端每周清單前端每周清單專注前端領(lǐng)域內(nèi)容,分為新聞熱點(diǎn)開發(fā)教程工程實(shí)踐深度閱讀開源項(xiàng)目巔峰人生等欄目。 前端每周清單第 12 期:支付寶前端構(gòu)建工具發(fā)展、LinkedIn用Brotli加快網(wǎng)頁響應(yīng)速度、餓了么PWA 升級實(shí)踐 為InfoQ中文站特供稿件,首發(fā)地址為這里;如需轉(zhuǎn)載,請與InfoQ中文站聯(lián)系。從屬于筆...

    liuchengxu 評論0 收藏0
  • 翻譯 | 擺脫瀏覽器限制的JavaScript

    摘要:在考慮宇航員的生命安全時,輕微的打嗝或者服務(wù)中斷都會釀成生死事故。也許最大的挑戰(zhàn)來自谷歌主導(dǎo)的簡稱。在最近的開發(fā)者峰會,以及今年的會議上,谷歌都為安排了大量討論。由微軟提供,是廣受歡迎的編輯器,到月份已經(jīng)獲得了超過五百萬用戶。 譯者:安冬 (滬江Web前端開發(fā)工程師)本文原創(chuàng)翻譯,轉(zhuǎn)載請注明作者及出處。原文地址:http://developer.telerik.com/... 技術(shù)世界...

    xfee 評論0 收藏0
  • 前端每周清單年度總結(jié)與盤點(diǎn)

    摘要:前端每周清單年度總結(jié)與盤點(diǎn)在過去的八個月中,我?guī)缀踔蛔隽藘杉?,工作與整理前端每周清單。本文末尾我會附上清單線索來源與目前共期清單的地址,感謝每一位閱讀鼓勵過的朋友,希望你們能夠繼續(xù)支持未來的每周清單。 showImg(https://segmentfault.com/img/remote/1460000010890043); 前端每周清單年度總結(jié)與盤點(diǎn) 在過去的八個月中,我?guī)缀踔蛔隽?..

    jackwang 評論0 收藏0
  • 王下邀月熊_Chevalier的前端每周清單系列文章索引

    摘要:感謝王下邀月熊分享的前端每周清單,為方便大家閱讀,特整理一份索引。王下邀月熊大大也于年月日整理了自己的前端每周清單系列,并以年月為單位進(jìn)行分類,具體內(nèi)容看這里前端每周清單年度總結(jié)與盤點(diǎn)。 感謝 王下邀月熊_Chevalier 分享的前端每周清單,為方便大家閱讀,特整理一份索引。 王下邀月熊大大也于 2018 年 3 月 31 日整理了自己的前端每周清單系列,并以年/月為單位進(jìn)行分類,具...

    2501207950 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<