什么是Nodejs
- Nodejs是c++編寫的呢铆,采用Chrome瀏覽器V8引擎哈恰,本質(zhì)上是JavaScript運(yùn)行環(huán)境
- 可以解析JS代碼(沒有瀏覽器安全級(jí)限制)
- 提供系統(tǒng)級(jí)別的API
- 文件的讀寫
- 進(jìn)程的管理
- 網(wǎng)路通信
Node模塊分類
- 核心模塊 http fs path
- 文件模塊 var util = require('./util.js')
- 第三方模塊var promise =require('bluebird')(通過npm install)
模塊的流程
- 創(chuàng)建模塊 teacher.js
- 導(dǎo)出模塊 exports.add = function(){}
- 加載模塊 var teacher = require('./teacher.js')
- 使用模塊 teacher.add('May')
Node.js API
- url網(wǎng)址解析
- url.parse('xxxxxx')
- protocol:http/https
- port:端口號(hào)
- host:主機(jī)
- hostname:主機(jī)名
- hash:哈希#
- search:查詢塘慕?
- path
- pathname
- href
- url.parse('xxxx',true) 使用querystring
- url.format({})//和parse反向操作
- url.resolve()//生產(chǎn)合法url鏈接地址
- url.parse('xxxxxx')
- querystring
- querystring.stringify({name:'scott',course:['jade','node'],from:''})
=>'name=scott&course=jade&course=node&from=' - querystring.stringify({name:'scott',course:['jade','node'],from:''},',')
=>'name=scott,course=jade,course=node,from=' - querystring.stringify({name:'scott',course:['jade','node'],from:''},',',':')
=>'name:scott,course:jade,course:node,from:' - querystring.parse('name=scott&course=jade&course=node&from=')
=> { name: 'scott', course: [ 'jade', 'node' ], from: '' } - querystring.parse('name=scott,course=jade,course=node,from=',',')
- querystring.parse('name:scott,course:jade,course:node,from:',',',':')
- querystring.escape('xxx') // 轉(zhuǎn)義
- querystring.unescape('xxxxx') //反轉(zhuǎn)義
- querystring.stringify({name:'scott',course:['jade','node'],from:''})
HTTP知識(shí)
-
http請(qǐng)求過程
- http客戶端發(fā)起請(qǐng)求荞怒,創(chuàng)建端口
- http服務(wù)器在端口監(jiān)聽客戶端請(qǐng)求
- http服務(wù)器向客戶端返回狀態(tài)和內(nèi)容
-
瀏覽器做了哪些操作
- chrome搜做自身DNS緩存(chrome://net-internals/#dns)
- 如果瀏覽器沒有找到緩存或者緩存已失效轴或,chrome會(huì)搜索操作系統(tǒng)自身的DNS緩存
- 讀取本地的HOST文件
- 瀏覽器發(fā)起一個(gè)DNS的一個(gè)系統(tǒng)調(diào)用
- 寬帶運(yùn)營(yíng)商服務(wù)器查看本身緩存
- 運(yùn)營(yíng)商服務(wù)器發(fā)一個(gè)迭代DNS解析的請(qǐng)求瓦戚,運(yùn)營(yíng)商服務(wù)器把結(jié)果返回操作系統(tǒng)內(nèi)核同時(shí)緩存起來;操作系統(tǒng)內(nèi)核把結(jié)果返回瀏覽器摸吠;最終瀏覽器拿到了www.imooc.com對(duì)應(yīng)的ip地址
- 瀏覽器獲得域名對(duì)應(yīng)的IP地址后,發(fā)起HTTP"三次握手"
- TCP/IP連接建立起來后嚎花,瀏覽器就可以向服務(wù)器發(fā)送HTTP請(qǐng)求了
- 服務(wù)器端接收到了這個(gè)請(qǐng)求寸痢,根據(jù)路徑參數(shù),經(jīng)過后端的一些處理之后紊选,把處理后的一個(gè)結(jié)果的數(shù)據(jù)返回給瀏覽器
- 瀏覽器進(jìn)行解析和渲染
-
http結(jié)構(gòu)組成
無論是請(qǐng)求和響應(yīng)啼止,都由HTTP頭和正文組成- HTTP頭:發(fā)送一些附加信息,如內(nèi)容類型兵罢,服務(wù)器發(fā)送相應(yīng)的日期献烦,HTTP狀態(tài)碼等
- 正文:用戶提交的表單數(shù)據(jù)或者返回的數(shù)據(jù)
-
http請(qǐng)求方法
- get:用于獲取或者讀取數(shù)據(jù)
- post:向指定的資源提交數(shù)據(jù)
-
http狀態(tài)碼
- 1xx 代表請(qǐng)求已經(jīng)接收了,正在處理
- 2xx 表示請(qǐng)求已經(jīng)接收卖词,并且處理了
- 3xx 表示重定向巩那,表示請(qǐng)求的時(shí)候需要更進(jìn)一步的重定向頁(yè)面
- 4xx 表示請(qǐng)求有錯(cuò)誤,請(qǐng)求有語法錯(cuò)誤,請(qǐng)求無法實(shí)現(xiàn)
- 5xx 表示服務(wù)器端的錯(cuò)誤,服務(wù)器端接收到請(qǐng)求但是處理出現(xiàn)問題
常見請(qǐng)求碼
- 200: 客戶端請(qǐng)求成功优妙;
- 400:客戶端請(qǐng)求有語法錯(cuò)誤哩俭;
- 401:請(qǐng)求沒經(jīng)過授權(quán);
- 403:服務(wù)器收到請(qǐng)求窿春,但拒絕提供服務(wù),可能是沒有權(quán)限等等;
- 404:資源沒找到页藻;
- 500:服務(wù)器端錯(cuò)誤;
- 503:服務(wù)器端當(dāng)下還不能處理客戶端這個(gè)請(qǐng)求植兰,過段時(shí)間恢復(fù)正常份帐。
-
node中的http模塊
- 什么是回調(diào)
將后續(xù)邏輯封裝在函數(shù)回調(diào)中作為起始函數(shù)的參數(shù),逐層去嵌套,通過這種方式讓函數(shù)按照我們所期望的方式走完整個(gè)流程 - 什么是異步和同步
同步是程序執(zhí)行一個(gè)任務(wù)楣导,后一個(gè)任務(wù)等待前一個(gè)任務(wù)完成后再執(zhí)行弥鹦,同步的執(zhí)行順序和任務(wù)的排列順序是一致的
異步任務(wù)的排列順序和執(zhí)行順序無關(guān),程序執(zhí)行完成后是執(zhí)行回調(diào)函數(shù),常見異步函數(shù)setTimeOut和setInterval - 什么是阻塞和非阻塞
阻塞是當(dāng)你打電話問個(gè)請(qǐng)求時(shí)彬坏,那邊說你等等我給你查查朦促,這時(shí)候你電話仍然是掛起的,等待等待栓始,直到拿到結(jié)果务冕。
非阻塞是打電話過去問,然后掛電話幻赚,等那邊找到結(jié)果或打電話給你禀忆,你該干嘛就干嘛。在node.js里面單線程可以通過回調(diào)函數(shù)來做異步操作落恼,達(dá)到非阻塞的效果箩退。 - 什么是單線程和多線程
單線程:只有執(zhí)行上一個(gè)任務(wù)完成后,下一個(gè)才能執(zhí)行佳谦。優(yōu)點(diǎn)是安全戴涝。
多線程:同時(shí)執(zhí)行多個(gè)函數(shù),缺點(diǎn)是容易爭(zhēng)搶資源钻蔑,有管理和分配資源的難度啥刻。 - 什么是事件和事件驅(qū)動(dòng)
nodeJs中客戶端連接到服務(wù)器端時(shí)會(huì)觸發(fā)事件。打開文件也會(huì)觸發(fā)事件等咪笑,所有能夠觸發(fā)事件的都是EventEmitter下的實(shí)例可帽;先注冊(cè)事件,等事件被觸發(fā)的時(shí)候窗怒,才執(zhí)行事件回調(diào)映跟。這種形式就是事件驅(qū)動(dòng)。 - 什么是事件循環(huán)
EventLoop是事件管理機(jī)制扬虚,當(dāng)存在很多異步操作申窘、IO操作時(shí),會(huì)被壓入EventLoop隊(duì)列孔轴,有個(gè)單線程不斷查詢隊(duì)列中是否有事件
- 什么是回調(diào)
HTTP性能小測(cè)試
使用Apache ab
ab -n1000 -c10 https:www.imooc.com/
// -n 1000 總請(qǐng)求數(shù)是1000個(gè)
// -c10 并發(fā)數(shù)為10
/**
* 一個(gè)初級(jí)爬蟲Demo
*/
var https = require('https');
var cheerio = require('cheerio');
var url = 'https://www.imooc.com/learn/348';
// 請(qǐng)求url地址,獲取頁(yè)面html
https.get(url,function (res) {
var html = '';
res.on('data',function(data){
html += data;
});
res.on('end',function () {
var courseData = filterCharpter(html);
printChapter(courseData);
});
res.on('error',function () {
console.log('系統(tǒng)異常');
})
})
// 獲取頁(yè)面章節(jié)的函數(shù)
function filterCharpter (html) {
var $ = cheerio.load(html);
var chapters =$('.chapter');
var courseData = [];
chapters.each(function (value) {
var chapter = $(this);
var chapterTitle = chapter.find('strong').text().trim().split('\n')[0];
var videos = chapter.find('.video').children('li');
chapter = {
chapterTitle : chapterTitle,
videos:[]
}
videos.each(function(val){
var video = $(this).find('a').text().trim();
var videoName = video.split('\n')[0];
var videoTime = video.split('\n')[1].trim();
chapter.videos.push({name:videoName,time:videoTime});
});
courseData.push(chapter);
});
return courseData;
}
// 格式化打印頁(yè)面
function printChapter (courseData) {
courseData.forEach(function (val) {
var chapterTitle = val.chapterTitle;
console.log('章節(jié)標(biāo)題:'+chapterTitle+'\n');
val.videos.forEach(function (value) {
console.log(' '+value.name+'時(shí)長(zhǎng):'+value.time+'\n');
})
})
}
promise
針對(duì)異步場(chǎng)景的解決方案
-
Promise對(duì)象三種狀態(tài)
- 未完成(pending)
- 已完成(fulfilled/resolved)
- 失斕攴ā(rejected)
- 只能從pending->resolved或者pending->rejected
then方法
promise可以保證then的順序
then方法返回promise對(duì)象,兩個(gè)參數(shù)分別是成功回調(diào)函數(shù)和失敗回調(diào)函數(shù)路鹰。
promiseObj.then(onResolved,onRejected);
onResolved = function(value){
return promiseObj2;//返回一個(gè)promise對(duì)象
}
onRejected = function(err){}
- 基于promise的進(jìn)階版爬蟲(一次爬取多個(gè)文件)
var https = require('https');
var cheerio = require('cheerio');
var baseUrl = 'https://www.imooc.com/learn/'
var videosArray = [728,637,348,259,197,134,75];
videosArray = videosArray.map(item => baseUrl+item);
// 創(chuàng)建promise
function getPageAsync(url){
return new Promise(function(resolve,rejecte){
// 請(qǐng)求url地址,獲取頁(yè)面html
https.get(url,function (res) {
var html = '';
res.on('data',function(data){
html += data;
});
res.on('end',function () {
resolve(html);
});
res.on('error',function (error) {
rejecte(error);
})
})
})
}
// 獲取頁(yè)面章節(jié)的函數(shù)
function filterCharpter (html) {
var $ = cheerio.load(html);
var title = $('.course-infos h2').text().trim();
var page = {
title:title,
courseData:[]
}
var chapters =$('.chapter');
var courseData = [];
chapters.each(function (value) {
var chapter = $(this);
var chapterTitle = chapter.find('strong').text().trim().split('\n')[0];
var videos = chapter.find('.video').children('li');
chapter = {
chapterTitle : chapterTitle,
videos:[]
}
videos.each(function(val){
var video = $(this).find('a').text().trim();
var videoName = video.split('\n')[0];
var videoTime = video.split('\n')[1].trim();
chapter.videos.push({name:videoName,time:videoTime});
});
courseData.push(chapter);
});
page.courseData = courseData;
return page;
}
// 打印章節(jié)內(nèi)容
function printCourseData (coursesData) {
coursesData.forEach(function(item){
console.log('課程名:'+item.title+'\n');
item.courseData.forEach(function(val){
var chapterTitle = val.chapterTitle;
console.log(' '+chapterTitle+'\n');
val.videos.forEach(function (value) {
console.log(' '+value.name+'時(shí)長(zhǎng):'+value.time+'\n');
})
})
console.log('\n');
})
}
// 所有頁(yè)面的promise數(shù)組
var pagesPromiseArray = [];
videosArray.forEach(function(val){
pagesPromiseArray.push(getPageAsync(val));
})
//promise.all方法
Promise
.all(pagesPromiseArray)
.then(function (pages) {
var coursesData = [];
pages.forEach(function(html){
var courses = filterCharpter(html)
coursesData.push(courses)
})
printCourseData(coursesData);
})
.catch (function (e) {
console.log('程序異常');
})
Node API
-
Buffer 處理TCP/圖形/文件/網(wǎng)絡(luò)
- buffer[index]
- buffer.length
- buffer.write(string,[offset,length,encoding])
var buf = new Buffer('Hello World'); buf.length//11 buf.write('Hi World'); buf.toString()//'Hi Worldrld' 初始化時(shí)長(zhǎng)度被指定贷洲,不會(huì)清空后面內(nèi)容 buf.write(' Dingsusu lalala',2,16) buf.toString()//'Hi Dingsusu'
- buffer.copy(target[,targetStart,sourceStart,sourceEnd])
Stream 流,用來暫存和移動(dòng)數(shù)據(jù)