摘要:當(dāng)某個(gè)執(zhí)行完畢時(shí),將以時(shí)間的形式通知執(zhí)行操作的線程,線程執(zhí)行了這個(gè)事件的回調(diào)函數(shù)。為了處理異步,線程必須有事件循環(huán),不斷的檢查是否有未處理的時(shí)間。這種處理機(jī)制,稱為事件環(huán)機(jī)制。方面使用第三方模塊。
簡(jiǎn)介
V8引擎本身就是用于Chrome瀏覽器的JS解釋部分,但是Ryan Dahl,把V8搬到服務(wù)器,用于做服務(wù)器的軟件。
Node是一個(gè)專注于實(shí)現(xiàn)高性能Web服務(wù)器優(yōu)化的專家,在遇到V8而誕生的項(xiàng)目
沒有歷史包袱,沒有同步I/O。不會(huì)出現(xiàn)一個(gè)同步I/O導(dǎo)致事件循環(huán)性能急劇降低的情況。
V8性能足夠好,遠(yuǎn)遠(yuǎn)比Python,Ruby等其它腳本語言的引擎快。
JavaScript語言的閉包特性非常方便,比C中的回調(diào)函數(shù)好用。
Node可以讓JavaScript運(yùn)行在服務(wù)器端的平臺(tái)開發(fā),它讓JavaScript的觸角延伸到了服務(wù)器端,可以與PHP,JSP,Python,Ruby等語言實(shí)現(xiàn)后端開發(fā)。
但Node似乎有點(diǎn)不同:
Node不是一種獨(dú)立的語言,與PHP,JSP,Python,Perl,Ruby的“即使語言,也是平臺(tái)”不同,Node使用的是JavaScript進(jìn)行編程,運(yùn)行在JavaScript引擎上(V8)
與PHP,JSP等相比(PHP,JSP,.net都需要運(yùn)行在服務(wù)器程序上,Apache,Naginx,Tomcat,IIS),Node跳過了Apcahe,Naginx,IIS等HTTP服務(wù)器,它自己不用建設(shè)在任何服務(wù)器任何之上。Node的設(shè)計(jì)理念與經(jīng)典架構(gòu)(LAMP = Linux + Apache + MySQL + PHP) 有著很大的不同,可以提供強(qiáng)大的伸縮能力。
Node沒有Web容器。
Node是花最小的硬件成本,追求更高的并發(fā),更高的處理性能。
Node特點(diǎn)所謂特點(diǎn),就是Node如果解決服務(wù)器高性能瓶頸問題。
JavaScript有什么特點(diǎn)的時(shí)候,會(huì)立即想到 單線程,事件驅(qū)動(dòng), 面向?qū)ο?/b>。但是JavaScript精髓 覺得是 this, 閉包 ,作用域鏈, 函數(shù)。才使得這門語言魅力無窮。
單線程
在Java,PHP,或者.net 等服務(wù)器端語言中,會(huì)為每一個(gè)用戶端連接創(chuàng)建一個(gè)新的線程。而每個(gè)線程需要耗費(fèi)大約2MB內(nèi)存。理論上,一個(gè)8GB內(nèi)存的服務(wù)器可以同時(shí)連接的最大用戶數(shù)4000個(gè)左右。要讓W(xué)eb應(yīng)用程序支持更多的用戶,就需要增加服務(wù)器的數(shù)量,而Web應(yīng)用程序的硬件成本就上升了。
Node不為每個(gè)用戶連接創(chuàng)建一個(gè)新的線程,而僅僅使用一個(gè)線程。當(dāng)有用戶連接了,就觸發(fā)一個(gè)內(nèi)部事件,并通過非阻塞I/O,事件驅(qū)動(dòng)機(jī)制,讓Node程序宏觀上也是并行的。Node中,一個(gè)8GB內(nèi)存的服務(wù)器,可以同時(shí)處理超過4萬用戶的連接。
單線程好處:操作系統(tǒng)完全不再有線程創(chuàng)建,銷毀的時(shí)間開銷。
單線程壞處:就是一個(gè)用戶造成了線程的奔潰,整個(gè)服務(wù)都奔潰了,其它人的服務(wù)也就奔潰了。
單線程也能夠造成宏觀上的“并發(fā)”。
非阻塞I/O
非阻塞I/O non-blocking I/O
例子:訪問數(shù)據(jù)庫(kù)取得數(shù)據(jù)的時(shí)候,需要一段時(shí)間。
在傳統(tǒng)的單線程處理機(jī)制中,在執(zhí)行了訪問數(shù)據(jù)庫(kù)代碼之后,整個(gè)線程都將暫停下來,等待數(shù)據(jù)庫(kù)返回結(jié)果,才能執(zhí)行后面的代碼。也就是說I/O阻塞了代碼的執(zhí)行,極大降低了程序執(zhí)行的效率。
Node采用了非阻塞型I/O機(jī)制,因此在執(zhí)行了訪問數(shù)據(jù)庫(kù)的代碼之后,將立即轉(zhuǎn)而執(zhí)行后面的代碼,把數(shù)據(jù)庫(kù)返回的結(jié)果的處理代碼放在回調(diào)函數(shù)中,從而提高了程序的執(zhí)行效率。
當(dāng)某個(gè)I/O執(zhí)行完畢時(shí),將以時(shí)間的形式通知執(zhí)行I/O操作的線程,線程執(zhí)行了這個(gè)事件的回調(diào)函數(shù)。為了處理異步I/O,線程必須有事件循環(huán),不斷的檢查是否有未處理的時(shí)間。依次予以處理。
阻塞模式下,一個(gè)線程只能處理一項(xiàng)任務(wù),要想提高吞吐量必須通過多線程。而非阻塞模式下,一個(gè)線程永遠(yuǎn)在執(zhí)行計(jì)算操作,這個(gè)線程的CPU核心利用率永遠(yuǎn)是100%。 有一種類似 : 與其多人工作,但是好多人閑著,倒不如一個(gè)人工作,往死里干活。
事件驅(qū)動(dòng)
事件驅(qū)動(dòng) event-driven
在Node中,客戶端請(qǐng)求建立連接,提交數(shù)據(jù)等行為,會(huì)觸發(fā)相應(yīng)的時(shí)間。在Node中,在一個(gè)ie時(shí)時(shí)刻,只能執(zhí)行一個(gè)事件回調(diào)函數(shù),但是在執(zhí)行一個(gè)事件回調(diào)函數(shù)的中途,可以轉(zhuǎn)而處理其它事件(比如:有新用戶連接),然后返回繼續(xù)執(zhí)行原事件的回調(diào)函數(shù)。這種處理機(jī)制,稱為:"事件環(huán)"機(jī)制。
Node底層是C++(V8也是C++) 編寫。底層代碼中,近半數(shù)都用戶事件隊(duì)列,回調(diào)函數(shù)隊(duì)列的構(gòu)建。用事件驅(qū)動(dòng)來完成服務(wù)器的任務(wù)調(diào)度。用一個(gè)線程,擔(dān)負(fù)起了處理非常多的任務(wù)。
單線程,減少內(nèi)存開銷,操作系統(tǒng)的內(nèi)存換頁(yè)。
如某一個(gè)任務(wù),執(zhí)行了,但是被I/O阻塞了,所以這個(gè)縣城就阻塞了。非阻塞I/O,不會(huì)傻等I/O語句結(jié)束,而會(huì)執(zhí)行后面的語句。利用事件驅(qū)動(dòng),不管是新用戶的請(qǐng)求,還是老用戶的I/O完成,都將以事件方式加入事件環(huán)中,等待調(diào)度。
Node所有的I/O都是異步的,回調(diào)函數(shù)嵌套回調(diào)函數(shù)。
Node是單進(jìn)程單線程應(yīng)用程序,但是通過事件和回調(diào)支持并發(fā),所以性能非常高。
Node的每個(gè)API都是異步的,并作為一個(gè)獨(dú)立線程運(yùn)行,使用異步函數(shù)調(diào)用,并處理并發(fā)。
Node基本上所有的事件機(jī)制都是用設(shè)計(jì)模式中的觀察者模式實(shí)現(xiàn)的。
Node單線程類似進(jìn)入一個(gè)while(true)的事件循環(huán),直到?jīng)]有事件觀察者退出,每個(gè)異步事件都生成一個(gè)事件觀察者,如果有事件發(fā)生就調(diào)用該回調(diào)函數(shù)。
Node中,以模塊為單位劃分所有功能,并且提供一個(gè)完整的模塊加載機(jī)制,可以將應(yīng)用程序話費(fèi)為各個(gè)不同的部分。
Node中,一個(gè)JavaScript文件中定義的變量,函數(shù),都只在這個(gè)文件內(nèi)部有效果。
俠義的說,每一個(gè)JavaScript文件都是一個(gè)模塊,而多個(gè)JavaScript文件之間可以相互require,共同實(shí)現(xiàn)一個(gè)功能,整體外對(duì),又稱之為廣義上的模塊
好處:
減少重復(fù)代碼量,增加可讀性。
方便進(jìn)行代碼規(guī)劃。
方面使用第三方模塊。
當(dāng)需要從JS文件外部引用到這些變量,函數(shù)時(shí),必須使用exprots對(duì)象,或者module.exprots進(jìn)行暴露。使用者需要使用require(); 函數(shù)引入這個(gè)JS文件。
function People( name,sex,age ){ this.name = name; this.sex = sex; this.age = age; } People.prototype = { sayHello: function(){ console.log(this.name+this.sex+this.age); } }; // 暴露 module.exports = People;
// 使用 var People = require("./People.js"); var p1 = new People("zf","nv","23"); p1.sayHello();
一個(gè)JavaScript文件,可以向外exprots無數(shù)個(gè)變量,函數(shù),對(duì)象,但是require(); 的時(shí)候,僅僅需要 載入一次JS文件即可。 所以,無形之后,會(huì)增加一個(gè)頂層命名空間。
// 變量 // 需要變量引用 使用 exports.a = 10; // 直接需要變量值使用. module.exports = name; // 對(duì)象 module.exports = { name1: 123, name2: 456 } // 暴露結(jié)果: { name1: 123, name2: 456 } exports.msg = { name1: 1, name2: 2 } // 暴露結(jié)果 : { msg: { name1: 1, name2: 2 } } // 函數(shù) exports.showMsg = function () { } // 暴露結(jié)果 : { showMsg: [Function] } // 在 引用結(jié)果 需要 通過 變量 引用對(duì)象 執(zhí)行 // var msg = require(); // msg.showMsg(); module.exports = function () { } // 暴露結(jié)果 [Function] // 引入文件的 變量 直接執(zhí)行模板引擎
數(shù)據(jù)綁定,成為一個(gè)完整的HTML字符串。
Node中使用的模板:ejs 和 jade
后臺(tái)模板引擎:
// 模板中需要的數(shù)據(jù) var dictionary = { a:6, news : ["xixi","haha"] };HTTP模塊 主要類
Class: http.Server
var server = http.createServer();
server就是http.Server類的實(shí)例。
常用的方法有:
server.listen(port, [hostname], [backlog], [callback])
Class: http.ServerResponse
var server = http.createServer(function(req,res){ });
res就是 http.ServerResponse類的實(shí)例。
Class: http.IncomingMessage
``
var server = http.createServer(function(req,res){ });
``
req就是http.IncomingMessage類的實(shí)例。
可以使用on語法監(jiān)聽某個(gè)事件。
var http = require("http"); var server = http.createServer(); server.on("request",function ( req,res ) { res.setHeader("Content-type","text/html;charset=utf8"); if ( req.url == "/" ){ res.end("index"); } else { res.end("404"); } }); server.listen(8080,"localhost");req對(duì)象
每次上行請(qǐng)求頭對(duì)象
req.headers //HTTP上行請(qǐng)求頭
req.httpVersion // http請(qǐng)求的版本。現(xiàn)在基本上都是1.1 req.method // “GET”、”POST”就是請(qǐng)求的類型 req.url // 用戶請(qǐng)求的網(wǎng)址res對(duì)象
每次下行響應(yīng)對(duì)象
res.end() // 每次都要有這個(gè)語句,表示這次的發(fā)送已經(jīng)結(jié)束 // 參數(shù)必須是string、buffer(圖片、文件)。 res.write() // 就是寫HTTP下行請(qǐng)求的body res.setHeader() // 設(shè)置返回的報(bào)文頭部 res.statusCode = 404; // 設(shè)置狀態(tài)碼 res.writeHead() // 和res.setHeader差不多 res.writeHead(288 , {"Content-Type":"text/plain"});url模塊
作用內(nèi)置模塊,解析url,解析地址。 分析和解析 URL 的工具
url.parse()url.parse()就是用來解析網(wǎng)址,接收一個(gè)字符串,返回一個(gè)JSON:
var obj = url.parse("http://localhost:8080/a/b/c/1.html?name=ting&age=21");
url.parse方法第二個(gè)參數(shù)如果是true,那么返回的對(duì)象中的query就是json
query: { xingming: "xiaoming", age: "12" }querystring模塊
querystring模塊是專門用來解析GET請(qǐng)求的查詢字符串的。
console.log( qs.parse("name=ting&age=21&hobby=run&hobby=sing") ); // 返回:{ name: "ting", age: "21", hobby: [ "run", "sing" ] }path模塊
處理和轉(zhuǎn)換文件路徑的工具集,專門處理路徑
path.basename() 返回路徑中的文件名 path.dirname() 返回路徑中的文件夾名 path.extname() 返回路徑的拓展名 console.log( path.basename("/xixi/haha/a.html") ); //a.html console.log( path.extname("/xixi/haha/a.html") ); //.html console.log( path.dirname("/xixi/haha/a.html") ); ///xixi/hahafs模塊
文件處理模塊,可以讀文件,也可以寫文件
fs.readFile(); //讀取文件內(nèi)容 fs.readDir(); //讀取文件夾名 fs.appendFile(); //追加文件 fs.writeFile(); //寫入文件(覆蓋原有的) fs.rename(); //修改文件名自定義模塊
每一個(gè)js文件中可以看成是一個(gè)小小的模塊
require()誰,就會(huì)執(zhí)行誰。就相當(dāng)于調(diào)用一個(gè)函數(shù)。A require B, 先執(zhí)行B全部語句,然后執(zhí)行A的剩余語句。
require("./test/a.js");
每個(gè)js文件就是一個(gè)閉包,聲明的函數(shù)、變量只在這個(gè)js文件內(nèi)部有定義。
A require了 B , 那么B里面的所有路徑都要按照A的路徑寫。
如果需要使用到其它文件中的變量,使用exports暴露出去。
exports.*** = ***; testA .js var a = 100; exports.a = a;
主文件
var testA = requrie("./testA.js"); console.log( testA.a );
暴露唯一的接口,module.exports ,一般使用到構(gòu)造函數(shù)。
如果只有寫文件載入,會(huì)去默認(rèn)文件夾下:node_modules 尋找是否有當(dāng)前需要載入的文件
require("test.js");
也可以直接省略路徑、省略文件名,只寫文件夾名
require("aa");
實(shí)際上引用的是node_moduels文件夾里面的aa文件夾里面的index.js文件。
一般第三方模塊,都放入node_modules文件夾中。
配置信息:
{ "name": "my_package", //項(xiàng)目名字 "version": "1.0.0", //版本號(hào) "main": "index.js", //入口文件 "keywords": [], //關(guān)鍵詞,就是搜索什么npm上能夠顯示你 "author": "ag_dubs", //作者 "license": "ISC", //版權(quán)協(xié)議 "repository": { //代碼托管倉(cāng)庫(kù),這個(gè)會(huì)自動(dòng)生成一個(gè)連接 "type": "git", "url": "https://github.com/ashleygwilliams/my_package.git" }, "bugs": { //如果發(fā)現(xiàn)bug應(yīng)該交給誰 "url": "https://github.com/ashleygwilliams/my_package/issues" }, "dependencies": { "underscore": "*", "date-format" : "0.0.2" }, "homepage": "https://github.com/ashleygwilliams/my_package" //個(gè)人網(wǎng)站 }
最重要的信息是:依賴
{ "dependencies": { "underscore": "*", "date-format" : "^0.0.2" } }formidable
處理POST請(qǐng)求
// formidable 語法 var form = new formidable.IncomingForm(); // 設(shè)置上傳路徑 form.uploadDir = "./uploads"; form.parse(req, function(err, fields, files) { // fields是普通域,就是普通的文本框、單選按鈕、復(fù)選按鈕、textarea都存在這個(gè)對(duì)象里面 // files是上傳的文件信息 var newname = df("yyyyMMddhhmmssSSS", new Date()); fs.rename(files.touxiang.path , "./uploads/" + newname + ".jpg",function(err){ if(err){ res.end("error"); return ; } }); res.end("ok"); });爬蟲初級(jí)
需要的npm包:
express
request (后端發(fā)送請(qǐng)求的模塊)
cheerio (像前端一樣操作拉取回來的數(shù)據(jù))
爬蟲以及Robots協(xié)議介紹:
爬蟲,是中自動(dòng)獲取網(wǎng)頁(yè)內(nèi)容的程序。是搜索引擎的重要組成部分,因此搜索引擎優(yōu)化很大程度上就是針對(duì)爬蟲而做出的優(yōu)化。
robots.txt是一個(gè)文本文件,robots.txt是一個(gè)協(xié)議,不是一個(gè)命令。robots.txt是爬蟲要查看的第一個(gè)文件。robots.txt文件告訴爬蟲在服務(wù)器上什么文件是可以被查看的,搜索機(jī)器人就會(huì)按照該文件中的內(nèi)容來確定訪問的范圍。
var express = require("express"); var app = express(); var cheerio = require("cheerio"); app.get("/", function(req, res){ var request = require("request"); request("https://linxingzhang.com", function(err, response, body) { if (!err && response.statusCode == 200) { $ = cheerio.load(body); // 和jquery的$("body") 一樣 res.json({ panel: $("#link-panel li").length }); } }); }); app.listen(3000);
使用supervisor啟動(dòng)
> supervisor start app.js常用npm包
模塊名 | 鏈接地址 | 簡(jiǎn)介 |
---|---|---|
async | async | 異步操作管理 |
bl | bl | 二進(jìn)制數(shù)據(jù)解析 |
bluebird | bluebird | 異步操作管理 |
browserify | browserify | 發(fā)布瀏覽器可用的包 |
bunyan | bunyan | 日志(logging)管理 |
chai | chai | 斷言 |
chalk | chalk | 命令行彩色輸出 |
co | co | 異步流程管理 |
colors | colors | 命令行彩色輸出 |
commander | commander | 命令行工具 |
debug | debug | Debug輸出器 |
dockerode | dockerode | Docker管理 |
duplexify | duplexify | Stream流操作工具 |
event-stream | event-stream | Stream流操作工具 |
express | express | Server服務(wù)器框架 |
hapi | hapi | Server服務(wù)器框架 |
koa | koa | Server服務(wù)器框架 |
glob | glob | 文件名匹配 |
grunt | grunt | 構(gòu)建工具 |
gulp | gulp | 構(gòu)建工具 |
hyperquest | hyperquest | 輕量級(jí)HTTP客戶端 |
istanbul | istanbul | 測(cè)試用例覆蓋率分析 |
JSONStream | JSONStream | Stream流管理工具 |
levelup | levelup | LevelDB |
lodash | lodash | 函數(shù)式編程工具 |
log4js | log4js | 日志(logging)管理工具 |
minimatch | minimatch | 文件名匹配 |
minimist | minimist | 命令行操作 |
mocha | mocha | 單元測(cè)試 |
moment | moment | 日期時(shí)間輸出 |
mongodb | mongodb | MongoDB |
mysql | mysql | MySQL |
nconf | nconf | 配置工具 |
needle | needle | 輕量級(jí)HTTP客戶端 |
node-fetch | node-fetch | Fetch API |
nodemailer | nodemailer | Email客戶端 |
passport | passport | 登錄和認(rèn)證 |
pg | pg | Postgres |
pump | pump | Stream流管理工具 |
redis | redis | Redis |
request | request | HTTP客戶端 |
restify | restify | REST API搭建 |
socket.io | socket.io | WebSocket實(shí)時(shí)通信 |
split2 | split2 | Stream流管理工具 |
tape | tape | 單元測(cè)試 |
through2 | through2 | Stream流管理工具 |
underscore | underscore | 函數(shù)式編程工具 |
ws | ws | Websockets |
xml2js | xml2js | XML轉(zhuǎn)換為JavaScript |
http-server | http-server | 命令行的HTTP服務(wù)器 |
nrm | nrm | 更改NPM下載源 |
node-inspector | node-inspector | Node調(diào)試 |
supervisor | supervisor | 檢測(cè)Node進(jìn)程的服務(wù) |
nodemon | nodemon | 在文件有變化之后會(huì)自動(dòng)重啟服務(wù) |
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/86303.html
摘要:例如指定一些依賴到模塊中實(shí)現(xiàn)規(guī)范的模塊化,感興趣的可以查看的文檔。 CommonJS 定義了 module、exports 和 require 模塊規(guī)范,Node.js 為了實(shí)現(xiàn)這個(gè)簡(jiǎn)單的標(biāo)準(zhǔn),從底層 C/C++ 內(nèi)建模塊到 JavaScript 核心模塊,從路徑分析、文件定位到編譯執(zhí)行,經(jīng)歷了一系列復(fù)雜的過程。簡(jiǎn)單的了解 Node 模塊的原理,有利于我們重新認(rèn)識(shí)基于 Node 搭建的...
摘要:環(huán)境變量法通過上一節(jié)的源碼分析,我們知道了的作用,那么如何使用或者優(yōu)雅的使用來解決依賴加載問題呢嘗試一最為直接的是,修改系統(tǒng)的環(huán)境變量。 模塊加載痛點(diǎn) 大家也或多或少的了解node模塊的加載機(jī)制,最為粗淺的表述就是依次從當(dāng)前目錄向上級(jí)查詢node_modules目錄,若發(fā)現(xiàn)依賴則加載。但是隨著應(yīng)用規(guī)模的加大,目錄層級(jí)越來越深,若是在某個(gè)模塊中想要通過require方式以依賴名稱或相對(duì)路...
摘要:先天就缺乏一項(xiàng)功能模塊通過標(biāo)簽引入代碼的方式顯得雜亂無章,語言自身毫無組織和約束能力。與文件模塊區(qū)別地方在于它從內(nèi)存中加載緩存執(zhí)行結(jié)果的位置核心模塊在對(duì)象上,文件模塊在對(duì)象上未完待續(xù) javascript先天就缺乏一項(xiàng)功能:模塊 javasciprt 通過script標(biāo)簽引入代碼的方式顯得雜亂無章,語言自身毫無組織和約束能力。人們不得不用命名空間等方式人為地約束代碼,以求達(dá)到安全和易用的...
摘要:主要區(qū)別是需要在聲明模塊時(shí)指定所有的依賴,通過形參傳遞依賴到模塊內(nèi)容中。 前言 昨天,公司同事問了我如下一個(gè)問題: showImg(https://segmentfault.com/img/bVWXYP?w=548&h=346); 說他在看一個(gè)插件時(shí),看到了源碼結(jié)構(gòu)如截圖所示,他知道(function(){})()是一種立即執(zhí)行函數(shù),但是在截圖中,最后的那個(gè)圓括號(hào)里又寫了一個(gè)函數(shù)fun...
摘要:模塊載入策略的模塊分為兩類,一類為原生核心模塊,一類為文件模塊。最后傳入對(duì)象的,方法,,文件名,目錄名作為實(shí)參并執(zhí)行。在這個(gè)主文件中,可以通過方法去引入其余的模塊。以上所描述的模塊載入機(jī)制均定義在中。 CommonJS規(guī)范? 早在Netscape誕生不久后,JavaScript就一直在探索本地編程的路,Rhino是其代表產(chǎn)物。無奈那時(shí)服務(wù)端JavaScript走的路均是參考眾多服務(wù)器端...
閱讀 2171·2020-06-12 14:26
閱讀 2477·2019-08-29 16:41
閱讀 1885·2019-08-29 15:28
閱讀 2448·2019-08-26 13:43
閱讀 753·2019-08-26 13:37
閱讀 2773·2019-08-23 18:13
閱讀 2791·2019-08-23 15:31
閱讀 1014·2019-08-23 14:10