前端模板引擎有哪些(前端模板引擎一般用來(lái)開(kāi)發(fā)什么)
今天給各位分享前端模板引擎有哪些的知識(shí),其中也會(huì)對(duì)前端模板引擎一般用來(lái)開(kāi)發(fā)什么進(jìn)行解釋,如果能碰巧解決你現(xiàn)在面臨的問(wèn)題,別忘了關(guān)注本站,現(xiàn)在開(kāi)始吧!
本文目錄一覽:
- 1、現(xiàn)在前端流行的框架有什么??
- 2、前端開(kāi)發(fā)主要學(xué)習(xí)那些技術(shù)以適應(yīng)工作需求?
- 3、前端技術(shù)棧有哪些
- 4、js模板引擎事件怎么解決
現(xiàn)在前端流行的框架有什么??
現(xiàn)在前端主要流行三大框架。給大家具體分析一下這三個(gè)前端框架:
1、Angular
大家眼里比較“叼”的框架,甚至有人說(shuō)三大框架中只有她能稱的上一個(gè)完整的框架,因?yàn)樗臇|西比較完善,包含模板,數(shù)據(jù)雙向綁定,路由,模塊化,服務(wù),過(guò)濾器,依賴注入等所有功能。對(duì)于剛開(kāi)始學(xué)習(xí)使用框架的小伙伴們,可以推薦這個(gè)框架,學(xué)會(huì)之后簡(jiǎn)直能顛覆之前你對(duì)前端開(kāi)發(fā)的認(rèn)知。使用 TypeScript能夠提高代碼可維護(hù)性,有利于后期重構(gòu)。雙向數(shù)據(jù)流很方便,但是等業(yè)務(wù)復(fù)雜之后,你可能就搞不清楚數(shù)據(jù)流了。還有令人不開(kāi)心的臟值檢查,以及directive的封裝并沒(méi)有解決視圖與數(shù)據(jù)關(guān)系完全分離,有時(shí)候還要用$digist強(qiáng)制觸發(fā)檢測(cè)。
2、React
這個(gè)框架本身比較容易理解,他的結(jié)構(gòu)很清晰,就是由十幾個(gè)API組成,然后異步渲染,我們只需要處理好接口和維護(hù)就好了,但是很多人反映上手還是有一定的的難度的。React是單向數(shù)據(jù)流,代碼寫(xiě)起來(lái)會(huì)較雙向數(shù)據(jù)流的多一些,但是同樣的排查問(wèn)題時(shí)思路清晰很多。
3、Vue
號(hào)稱是最簡(jiǎn)單,最容易上手的框架,同時(shí)也是行內(nèi)的大趨勢(shì),還可以用來(lái)開(kāi)發(fā)最火的小程序。畢竟用這神器,代碼碼的飛快,項(xiàng)目也能快速上線。同時(shí)他也是雙向數(shù)據(jù)流。有些人認(rèn)為Vue是Angular和React的結(jié)合,既有Angular的模板語(yǔ)法也有React的組件化體系。
當(dāng)你學(xué)會(huì)其中某個(gè)框架之后,你再轉(zhuǎn)用其他框架的時(shí)候,學(xué)會(huì)是很容易的,因?yàn)榉椒ǘ际谴笸‘惖?。具體的使用還是得看公司的項(xiàng)目適合或者要求哪個(gè)框架。
前端開(kāi)發(fā)主要學(xué)習(xí)那些技術(shù)以適應(yīng)工作需求?
一、前端是什么?
前端即網(wǎng)站前臺(tái)部分,也叫前端開(kāi)發(fā),運(yùn)行在PC端,移動(dòng)端等瀏覽器上展現(xiàn)給用戶瀏覽的網(wǎng)頁(yè)。隨著互聯(lián)網(wǎng)技術(shù)的發(fā)展,HTML5,CSS3,前端框架的應(yīng)用,跨平臺(tái)響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)能夠適應(yīng)各種屏幕分辨率,完美的動(dòng)效設(shè)計(jì),給用戶帶來(lái)極高的用戶體驗(yàn)。
核心技術(shù)是前端開(kāi)發(fā)中最基本也是最必須的三個(gè)技能。前端的開(kāi)發(fā)中,在頁(yè)面的布局時(shí), HTML將元素進(jìn)行定義,CSS對(duì)展示的元素進(jìn)行定位,再通過(guò)JavaScript實(shí)現(xiàn)相應(yīng)的效果和交互。雖然表面看起來(lái)很簡(jiǎn)單,但這里面需要掌握的東西絕對(duì)不會(huì)少。在進(jìn)行開(kāi)發(fā)前,需要對(duì)這些概念弄清楚、弄明白,這樣在開(kāi)發(fā)的過(guò)程中才會(huì)得心應(yīng)手。
二、前端都需要學(xué)什么(可以分為八個(gè)階段)?
1、第一階段:
? HTML+CSS:
HTML進(jìn)階、 CSS進(jìn)階、p+CSS布局、HTML+CSS整站開(kāi)發(fā)、
? JavaScript基礎(chǔ):
Js基礎(chǔ)教程、js內(nèi)置對(duì)象常用方法、常見(jiàn)DOM樹(shù)操作大全、ECMAscript、DOM、BOM、定時(shí)器和焦點(diǎn)圖。
? JS基本特效:
常見(jiàn)特效、例如:tab、導(dǎo)航、整頁(yè)滾動(dòng)、輪播圖、JS制作幻燈片、彈出層、手風(fēng)琴菜單、瀑布流布局、滾動(dòng)事件、滾差視圖。
? JS高級(jí)特征:
正則表達(dá)式、排序算法、遞歸算法、閉包、函數(shù)節(jié)流、作用域鏈、基于距離運(yùn)動(dòng)框架、面向?qū)ο蠡A(chǔ)、
? JQuery:基礎(chǔ)使用
懸著器、DOM操作、特效和動(dòng)畫(huà)、方法鏈、拖拽、變形、JQueryUI組件基本使用。
2、第二階段:HTML5和移動(dòng)Web開(kāi)發(fā)
? HTML5:
HTML5新語(yǔ)義標(biāo)簽、HTML5表單、音頻和視頻、離線和本地存儲(chǔ)、SVG、Web Socket、Canvas.
? CSS3:
CSS3新選擇器、偽元素、臉色表示法、邊框、陰影、flex布局、background系列屬性改變、Transition、動(dòng)畫(huà)、景深和深透、3D效果制作、Velocity.js框架、元素進(jìn)場(chǎng)、出場(chǎng)策略、炫酷CSS3網(wǎng)頁(yè)制作。
? Bootstrap:
響應(yīng)式概念、媒體查詢、響應(yīng)式網(wǎng)站制作、刪格系統(tǒng)、刪格系統(tǒng)原理、Bootstrap常用模板、LESS和SASS。
? 移動(dòng)Web開(kāi)發(fā):
跨終端WEB和主流設(shè)備簡(jiǎn)介、視口、流式布局、彈性盒子、rem、移動(dòng)終端JavaScript事件、手機(jī)中常見(jiàn)JS效果制作、手機(jī)聚劃算頁(yè)面、手機(jī)滾屏。
3、第三階段:HTTP服務(wù)和AJAX編程
? WEB服務(wù)器基礎(chǔ):
服務(wù)器基礎(chǔ)知識(shí)、Apache服務(wù)器和其他WEB服務(wù)器介紹、Apache服務(wù)器搭建、HTTP介紹。
? AJAX上篇:
Ajax簡(jiǎn)介和異步的概念、Ajax框架的封裝、XMLHttpRequest對(duì)象詳細(xì)介紹方法、兼容性處理方法、Ajax框架的封裝、Ajax中緩存問(wèn)題、XML介紹和使用、會(huì)處理簡(jiǎn)單的GET或者POST請(qǐng)求、
? AJAX下篇:
JSON和JSON解析、數(shù)據(jù)綁定和模板技術(shù)、JSONP、跨域技術(shù)、圖片預(yù)讀取和lazy-load技術(shù)、JQuery框架中的AjaxAPI、使用Ajax實(shí)現(xiàn)爆布流案例額。
4、第四階段:面向?qū)ο筮M(jìn)階
? 面向?qū)ο蠼K極篇:
從內(nèi)存角度到理解JS面向?qū)ο?、基本類型、?fù)雜類型、原型鏈、ES6中的面向?qū)ο?、ES6中變量的作用域(let ,const(聲明變量只讀),塊級(jí)作用域),ES6中函數(shù)新特性。
? 面向?qū)ο笕筇卣鳎?/p>
繼承性、多態(tài)性、封裝性。
? 面向?qū)ο笾袆?chuàng)建對(duì)象的五種方法:
自定義對(duì)象 、工廠模式創(chuàng)建對(duì)象、構(gòu)造函數(shù)、 混合模式創(chuàng)造對(duì)象、JSO格式創(chuàng)建對(duì)象。
5、第五階段:封裝一個(gè)屬于自己的框架
? 框架封裝基礎(chǔ):
事件流、冒泡、捕獲、事件對(duì)象、事件框架、選擇框架。
? 框架封裝中級(jí):
運(yùn)動(dòng)原理、單物體運(yùn)動(dòng)框架、多物體運(yùn)動(dòng)框架、運(yùn)動(dòng)框架面向?qū)ο蠓庋b。
? 框架封裝高級(jí)和補(bǔ)充:
JQuery框架雛形、可擴(kuò)展性、模塊化、封裝屬于傳智自己的框架。
6、第六階段:模塊化組件開(kāi)發(fā)
? 面向組件編程:
面向組件編程的方式、面向組件編程的實(shí)現(xiàn)原理、面向組件編程實(shí)戰(zhàn)、基于組件化思想開(kāi)發(fā)網(wǎng)站應(yīng)用程序。
? 面向模塊編程:
AMD設(shè)計(jì)規(guī)范、CMD設(shè)計(jì)規(guī)范、RequireJS,LoadJS、淘寶的SeaJS。
7、第七階段:主流的流行框架
? Web開(kāi)發(fā)工作流:
GIT/SVN、Vue-cli腳手架、NPM/Bower依賴管理工具、Grunt/Gulp/Webpack。
? 前端主流框架:
Vue.js、Angular.js、React.JS、Bootstrap。
? 常用庫(kù):
React.js、Vue.js、JQuery.js。
8、第八階段:Node.js全棧開(kāi)發(fā):
? 快速入門:
Node.js發(fā)展、生態(tài)圈、Io.js、Linux/Windows/OS X環(huán)境配置、REPL環(huán)境和控制臺(tái)程序、異步編程,非阻塞I/O、模塊概念,模塊管理工具、開(kāi)發(fā)流程,調(diào)試,測(cè)試。
? 核心模塊和對(duì)象:
全局對(duì)象global,process,console,util、事件驅(qū)動(dòng),事件發(fā)射器、加密解密,路徑操作,序列化和反序列化、文件流操作、HTTP服務(wù)端與客戶端、Socket.IO。
? Web開(kāi)發(fā)基礎(chǔ):
HTTP協(xié)議,請(qǐng)求響應(yīng)處理過(guò)程、關(guān)系型數(shù)據(jù)庫(kù)操作和數(shù)據(jù)訪問(wèn)、非關(guān)系型數(shù)據(jù)庫(kù)操作和數(shù)據(jù)訪問(wèn)、原生的Node.js開(kāi)發(fā)Web應(yīng)用程序、Web開(kāi)發(fā)工作流、Node.js開(kāi)發(fā)Blog案例。
? 快速開(kāi)發(fā)框架:
Express簡(jiǎn)介+MVC簡(jiǎn)介、Express常用API、Express路由模塊、Jade/Ejs模板引擎、使用Express重構(gòu)Blog案例、Koa等其他常見(jiàn)MVC框架。
? Node.js開(kāi)發(fā)電子商務(wù)實(shí)戰(zhàn):
需求與設(shè)計(jì)、賬戶模塊注冊(cè)登錄、會(huì)員中心模塊、前臺(tái)展示模塊、購(gòu)物車,訂單結(jié)算、在線客服即時(shí)通訊模塊。
前端技術(shù)棧有哪些
給大家介紹下web前端開(kāi)發(fā)需要掌握的知識(shí)點(diǎn),可以參考下。
1、PC端頁(yè)面制作與動(dòng)畫(huà)特效
學(xué)習(xí)HTML+CSS搭建網(wǎng)頁(yè)、CSS動(dòng)畫(huà)特效、PhotoShop切圖等基礎(chǔ)知識(shí),獲得初級(jí)Web前端工程師技能,主要進(jìn)行PC端網(wǎng)頁(yè)制作與樣式設(shè)計(jì)實(shí)現(xiàn),能夠配合UI設(shè)計(jì)師進(jìn)行項(xiàng)目開(kāi)發(fā)。
2、移動(dòng)端頁(yè)面制作與響應(yīng)式實(shí)現(xiàn)
講解移動(dòng)端布局與設(shè)備適配、響應(yīng)式設(shè)計(jì)與實(shí)現(xiàn)等,獲得移動(dòng)端頁(yè)面適配工程師技能,主要進(jìn)行移動(dòng)端網(wǎng)頁(yè)的布局制作與樣式設(shè)計(jì)實(shí)現(xiàn)??梢赃m配各種手機(jī)尺寸,并能利用響應(yīng)式進(jìn)行移動(dòng)端與PC端適配。
3、JavaScript與jQuery開(kāi)發(fā)
同HTML5基礎(chǔ)知識(shí)一樣,JavaScript開(kāi)發(fā)與jQuery開(kāi)發(fā)是職業(yè)晉升必備的技能包,獲得中級(jí)Web開(kāi)發(fā)工程師技能,主要進(jìn)行頁(yè)面行為交互,實(shí)現(xiàn)網(wǎng)站常見(jiàn)特效,加輪播圖,選項(xiàng)卡,拖拽效果等,并能配合UI和后端進(jìn)行項(xiàng)目開(kāi)發(fā)。
4、HTML5高級(jí)框架技術(shù)開(kāi)發(fā)
常用的Vue框架開(kāi)發(fā),React框架開(kāi)發(fā),Angular框架開(kāi)發(fā),數(shù)據(jù)可視化技術(shù)。可獲得中級(jí)Web前端工程師技能,主要適用框架開(kāi)發(fā)企業(yè)項(xiàng)目,實(shí)現(xiàn)單頁(yè)面應(yīng)用開(kāi)發(fā)??梢酝瓿蓮?fù)雜的數(shù)據(jù)交互應(yīng)用場(chǎng)景,具備獨(dú)立開(kāi)發(fā)項(xiàng)目能力。
5、全棧前后端技術(shù)開(kāi)發(fā)
Node.JS技術(shù),其他后端技術(shù),如Java或PHP??色@得高級(jí)Web前端工程師技能,主要進(jìn)行前后端全棧樣式開(kāi)發(fā),能獨(dú)立完成一個(gè)中小型項(xiàng)目的前后臺(tái),對(duì)于網(wǎng)站開(kāi)發(fā)有著非常熟練的編程能力。
可以從零開(kāi)始,一步步的掌握前端開(kāi)發(fā)的各項(xiàng)相關(guān)技能,最終達(dá)到企業(yè)對(duì)初級(jí)前端開(kāi)發(fā)工程師、中級(jí)前端開(kāi)發(fā)工程師、高級(jí)開(kāi)發(fā)工程師等職位的要求。
js模板引擎事件怎么解決
前端
深入node.js 3 模板引擎原理 事件 文件操作 可讀流的實(shí)現(xiàn)原
模板引擎是基于new Function + with 實(shí)現(xiàn)的。
ejs使用
實(shí)現(xiàn):
思路:借助fs的readFile先讀取文件內(nèi)容,然后使用正則表達(dá)式替換掉即可。
打印的結(jié)果是一樣的。
復(fù)雜的情況呢?拼接字符串,拼成想要的代碼
主要難點(diǎn)就是在字符串的拼接,第二部分,將全文分為三部分,然后拼接對(duì)應(yīng)的,如
let str = "";
with(obj){
str+= `!DOCTYPE html
html lang="en"
head
meta charset="UTF-8"
meta http-equiv="X-UA-Compatible" content="IE=edge"
meta name="viewport" content="width=device-width, initial-scale=1.0"
titleDocument/title
/head
body
`
arr.forEach(item={
str+=`
li
${item}
/li
`
})
str+=`
/body
/html`}
return str
登錄后復(fù)制
這就是拼出來(lái)的字符串,然后再new Function,包裹一層函數(shù),將with的obj傳入,返回str。
大概長(zhǎng)這樣。
效果就是:
所以本質(zhì)就是將獲取到的內(nèi)容,使用正則表達(dá)式匹配,拼接字符串成我們想要的內(nèi)容,用with包裹,改變內(nèi)部作用域,再通過(guò)new Function將str包裝成一個(gè)函數(shù),傳入對(duì)應(yīng)的值給obj。然后運(yùn)行之后str就能正常通過(guò)作用域獲取值賦值。
buffer
在服務(wù)端,需要一個(gè)東西來(lái)標(biāo)識(shí)內(nèi)存,但不能是字符串,因?yàn)樽址疅o(wú)法標(biāo)識(shí)圖片。node中使用buffer來(lái)標(biāo)識(shí)內(nèi)存的數(shù)據(jù)。他把內(nèi)存轉(zhuǎn)換成了16進(jìn)制來(lái)顯示(16進(jìn)制比較短)buffer每個(gè)字節(jié)的取值范圍就是0-0xff(十進(jìn)制的255).
node中buffer可以和字符串任意的轉(zhuǎn)換(可能出現(xiàn)亂碼)
編碼規(guī)范:ASCII - GB8030/GBK - unicode - UTF8
Buffer代表的是內(nèi)存,內(nèi)存是一段固定空間,產(chǎn)生的內(nèi)存是固定大小,不能隨意增加。
擴(kuò)容:需要?jiǎng)討B(tài)創(chuàng)建一個(gè)新的內(nèi)存,把內(nèi)容遷移過(guò)去。
創(chuàng)建一個(gè)長(zhǎng)度為5的buffer,有點(diǎn)像數(shù)組,但是數(shù)組可以擴(kuò)展,而buffer不可以擴(kuò)展。
還有一種聲明buffer。
Buffer.form。
一般使用alloc來(lái)聲明一個(gè)buffer,或者把字符串轉(zhuǎn)換成Buffer使用。文件操作也是采用Buffer形式。
buffer使用
無(wú)論是二進(jìn)制還是16進(jìn)制,表現(xiàn)得東西是一樣的。
base64編碼:
base64可以放在任何路勁的鏈接里,可以減少請(qǐng)求次數(shù)。但是文件大小會(huì)變大。比如webpack中的asset/type,把一些小的文件轉(zhuǎn)換成了Base64編碼內(nèi)嵌到了文件當(dāng)中,雖然可以減少請(qǐng)求次數(shù),但也增大了文件的大小。
base64的來(lái)源就是將每個(gè)字節(jié)都轉(zhuǎn)化為小于64的值。沒(méi)有加密功能,因?yàn)橐?guī)則很簡(jiǎn)單。如
第一步:將buffer中每個(gè)位置的值轉(zhuǎn)為二進(jìn)制。如上。
一個(gè)字節(jié)有八位,八位的最大值是255,有可能超過(guò)64。而base64編碼是要將每個(gè)字節(jié)轉(zhuǎn)化為小于64的值。所以就取每個(gè)字節(jié)的6位。6位的最大值就是2*6 - 1 = 63。也就是:
第二步:將38的形式轉(zhuǎn)成64的,保證每個(gè)字節(jié)小于64。將其轉(zhuǎn)為十進(jìn)制。
第三步,通過(guò)特定的編碼規(guī)則轉(zhuǎn)換即完成。
將我們獲取到的十進(jìn)制傳入,因?yàn)槊總€(gè)字節(jié)都是小于64的,所以不超過(guò)。
完成。
buffer的常用方法
除了form和alloc還有
slice
// slice
const a = Buffer.from([1,2,3,4,5])
const d = a.slice(0,2)
d[1] = 4
console.log(d);
console.log(a);
登錄后復(fù)制
與數(shù)組的用法相同,但是他并不是淺復(fù)制,而是直接關(guān)聯(lián)在一起。改變d也會(huì)改變a。而數(shù)組的slice是淺復(fù)制。改變?cè)紨?shù)據(jù)的值不會(huì)改變。
copy
將Buffer的數(shù)據(jù)拷貝到另一個(gè)數(shù)據(jù)上。
const a = Buffer.from([1, 2, 3, 4, 5]);
const d = Buffer.alloc(5);
a.copy(d, 1, 2, 3); //四個(gè)參數(shù),拷貝到哪里?從d的第一個(gè)開(kāi)始拷貝 a的a[2]-a[3]
console.log(d);
登錄后復(fù)制
copy四個(gè)參數(shù),分別是拷貝的目標(biāo)d。從d的第幾個(gè)長(zhǎng)度開(kāi)始??截恆的第2到第3位。
所以應(yīng)該是 Buffer 00 03 00 00 00
concat
用于拼接buffer
Buffer.concat(arr, index)
第二個(gè)參數(shù)是拼接出來(lái)的Buffer的長(zhǎng)度,如果大于原本的長(zhǎng)度,用00填寫(xiě)。
Buffer.myConcat = function (
bufferList,
length = bufferList.reduce((a, b) = a + b.length, 0)
) {
let bigBuffer = Buffer.alloc(length);
let offset = 0;
bufferList.forEach((item) = {
//使用copy每次拷貝一份然后offset向下走。
item.copy(bigBuffer, offset);
offset += item.length;
});
return bigBuffer
};
登錄后復(fù)制
借助copy,逐個(gè)拷貝一份即可。
文件操作
fs模塊有兩種基本api,同步,異步。
io操作,input,output,輸入輸出。
讀取時(shí)默認(rèn)是buffer類型。
寫(xiě)入的時(shí)候,默認(rèn)會(huì)將內(nèi)容以u(píng)tf8格式寫(xiě)入,如果文件不存在則創(chuàng)建。
讀取的data是Buffer類型,寫(xiě)入的是utf8格式。
這種讀寫(xiě)適合小文件
讀取文件某段內(nèi)容的辦法
fs.open用于打開(kāi)一個(gè)文件。fs.read用來(lái)讀取內(nèi)容并且寫(xiě)入到buffer中。
fs.write用于將內(nèi)容寫(xiě)入某個(gè)文件之中。如上,打開(kāi)了b.txt,然后用fs.wirte。五個(gè)參數(shù),分別是fd,buffer,從buffer的第0個(gè)位置,到buffer的第0個(gè)位置,從b.txt的第0位開(kāi)始寫(xiě),回調(diào)函數(shù)。
寫(xiě)入成功。
這種寫(xiě)法也不太美觀,每次都需要fs.open然后fs.read或者fs.wirte,容易造成回調(diào)地獄。
流 Stream的出現(xiàn)
源碼的實(shí)現(xiàn)步驟:
fs的CreateReadStrem是new了一個(gè)ReadStream,他是基于Stream的Readable類的,然后自己實(shí)現(xiàn)了_read方法。供Stream.prototype.read調(diào)用。
1 內(nèi)部會(huì)先open文件,然后直接直接繼續(xù)讀取操作,默認(rèn)是調(diào)用了pause暫停。
2 監(jiān)聽(tīng)用戶是否綁定了data事件,resume,是的話開(kāi)始讀取事件
3 調(diào)用fs.read 將數(shù)據(jù)讀取出來(lái)。
4 調(diào)用this.push去emit data事件,然后判斷是否可以讀取更多再去讀取。
第一種: fs.readFile(需要將文件讀取到磁盤中,占用內(nèi)容)=fs.wirteFile
第二種: fs.open = fs.read = fs.write 回調(diào)地獄。
實(shí)現(xiàn)讀取三個(gè)字節(jié)寫(xiě)入三個(gè)字節(jié)。采用fs.open fs.read fs.write的方法。
實(shí)現(xiàn)copy方法。
看實(shí)現(xiàn):
首先創(chuàng)建一個(gè)三字節(jié)的Buffer。
然后使用fs.open打開(kāi)要讀取和要寫(xiě)入的文件。
因?yàn)槲覀兪敲咳齻€(gè)每三個(gè)讀取,所以需要采用遞歸方式,一直讀取文件。
直到讀取完畢,調(diào)用回調(diào)函數(shù)。fs.read和fs.write的參數(shù)都是類似的,即fd,buffer,buffer的start,buffer的end,讀取文件/寫(xiě)入文件的start、回調(diào)函數(shù)(err,真正讀取到的個(gè)數(shù)/真正寫(xiě)入的個(gè)數(shù))
現(xiàn)在基本實(shí)現(xiàn)了讀一部分,寫(xiě)一部分,但是讀寫(xiě)的邏輯寫(xiě)在一起了,需要把他拆開(kāi)。
流 Stream模塊
可讀流
不是一下子把文件都讀取完畢,而是可以控制讀取的個(gè)數(shù)和讀取的速率。
流的概念跟fs沒(méi)有關(guān)系,fs基于stream模塊底層擴(kuò)展了一個(gè)文件讀寫(xiě)方法。
所以fs.open,fs.read等需要的參數(shù),createReadStream也需要、
返回一個(gè)對(duì)象,獲取需要監(jiān)聽(tīng)data事件。
close事件在end事件之后觸發(fā)。
由此可以看出:流的內(nèi)部基于 fs.open fs.close fs.read fs.write以及事件機(jī)制。
暫停是不再觸發(fā)data事件
rs.resume()是恢復(fù)。
實(shí)現(xiàn)readStream
從vscode調(diào)試源碼得知
實(shí)現(xiàn)思路:
createReadStream內(nèi)部new了一個(gè)ReadStream的實(shí)例,ReadStream是來(lái)自于Stream模塊。
做一系列參數(shù)默認(rèn)后, 調(diào)用this.open方法,這個(gè)方法會(huì)去調(diào)用fs.open去打開(kāi)文件,打開(kāi)之后觸發(fā)事件,從回調(diào)的形式發(fā)布訂閱模式,然后監(jiān)聽(tīng)事件,當(dāng)發(fā)現(xiàn)有用戶注冊(cè)了data事件之后,調(diào)用fs.read,j監(jiān)聽(tīng)open事件,在open之后再去讀取文件等等。
這樣我們的讀寫(xiě)邏輯就分離開(kāi)了,從回調(diào)的形式變成了發(fā)布訂閱模式,有利于解耦。
第一步:
第一步:參數(shù)初始化,并調(diào)用fs.open
open打開(kāi)之后會(huì)觸發(fā)open事件,注意,這里是異步的
第二步: 監(jiān)聽(tīng)用戶注冊(cè)的data事件,當(dāng)用戶注冊(cè)了data事件才去調(diào)用fs.read。調(diào)用this.read的時(shí)候open還沒(méi)完成。
所以第一次read的時(shí)候需要判斷,然后只監(jiān)聽(tīng)一次open事件,重復(fù)打開(kāi)read事件。
這個(gè)end和start配合,表示讀取文件從哪到哪的位置,但是end是包后的,比如上面的end為4,實(shí)際上讀取到的是5。
創(chuàng)建buffer存放讀取的內(nèi)容,再判斷應(yīng)該讀取多少內(nèi)容,以哪個(gè)小為準(zhǔn)。
然后打開(kāi)fs.read。將讀取到的buffer發(fā)布出去。再次調(diào)用this.read去繼續(xù)讀取。
start=1,end=4,讀取到2345的內(nèi)容,正確。
不給end,每次3個(gè)3個(gè)的讀取。
接著實(shí)現(xiàn)暫停,需要一個(gè)開(kāi)關(guān)。
這樣就基本完成了。
總結(jié):
一開(kāi)始實(shí)現(xiàn)的的copy方法,也是利用fs.open, fs.read, fs.write等,通過(guò)回調(diào)的形式完成的,這樣雖能完成,但是內(nèi)聚度較高,容易形成回調(diào)地獄。
而基于fs模塊,和events模塊,實(shí)現(xiàn)的可讀流,可以有效的解耦剛才的代碼,通過(guò)發(fā)布訂閱模式,在一開(kāi)始訂閱事件,在每個(gè)時(shí)間點(diǎn)對(duì)應(yīng)發(fā)布事件,然后代碼執(zhí)行,各司其職。
open和close是文件流獨(dú)有的,
可讀流具備:on (‘data’ | ‘end’ | ‘error’), resume, pause這些方法。
相關(guān)代碼:
// copy
const fs = require("fs");
const path = require("path");
// let buf = Buffer.alloc(3);
// //open打開(kāi)一個(gè)文件,第一個(gè)參數(shù)是路勁,第二個(gè)參數(shù)是打開(kāi)文件用途,第三個(gè)是回調(diào)函數(shù)。
// fs.open(path.resolve(__dirname, "a.txt"), "r", function (err, fd) {
// // fd 是file descriptor文件描述
// console.log("fd", fd);
// //讀取a.txt的內(nèi)容,并且將內(nèi)容寫(xiě)入buf中的第0個(gè)位置到3第三個(gè)位置,從a.txt的第六個(gè)位置開(kāi)始
// fs.read(fd, buf, 0, 3, 3, function (err, data) {
// fs.open(path.resolve(__dirname, "./b.txt"), "w", function (err, fd2) {
// fs.write(fd2, buf, 0, 3, 0, function (err, data2) {
// console.log("buf", buf);
// console.log("data2", data2);
// });
// });
// });
// });
function copy(source, target, cb) {
const BUFFER_SIZE = 3;
const buffer = Buffer.alloc(BUFFER_SIZE);
//每次讀入文件的位置
let r_offset = 0;
//每次寫(xiě)入新文件的位置
let w_offset = 0;
//讀取一部分?jǐn)?shù)據(jù),寫(xiě)入一部分?jǐn)?shù)據(jù)
//第三個(gè)參數(shù)可以是權(quán)限 權(quán)限有三個(gè)組合 rwx 可讀可寫(xiě)可執(zhí)行 r的權(quán)限是4,w的權(quán)限是2,x的權(quán)限是1 421 = 777 可寫(xiě)可讀可執(zhí)行
// 0o666表示最大的權(quán)限,默認(rèn)不用寫(xiě)。
//讀取的文件必須要存在。寫(xiě)入文件不存在會(huì)創(chuàng)建,如果文件有內(nèi)容會(huì)清空。
fs.open(source, "r", function (err, fd1) {
//打開(kāi)寫(xiě)的文件
fs.open(target, "w", function (err, fd2) {
//每次讀取三個(gè)寫(xiě)入三個(gè),回調(diào)的方式實(shí)現(xiàn)的功能,需要用遞歸
// 同步代碼則可以采用while循環(huán)
function next() {
fs.read(
fd1,
buffer,
0,
BUFFER_SIZE,
r_offset,
function (err, bytesRed) {
// bytesRed真正讀取到的個(gè)數(shù)
if (err) {
cb("讀取失敗");
return;
}
if (bytesRed) {
//將讀取到的內(nèi)容寫(xiě)入target目標(biāo)
fs.write(
fd2,
buffer,
0,
bytesRed,
w_offset,
function (err, written) {
if (err) retrun;
// written 真正寫(xiě)入的個(gè)數(shù)
r_offset += bytesRed; //每次寫(xiě)入之后,下一次讀取的內(nèi)容就該往前進(jìn)
w_offset += written;
next();
}
);
} else {
//讀取內(nèi)容為空,結(jié)束
fs.close(fd1, () = {});
fs.close(fd2, () = {});
cb();
}
}
);
}
next();
});
});
}
copy("./a.txt", "b.txt", (err, data) = {
console.log("copy success");
});
登錄后復(fù)制
createStream的實(shí)現(xiàn)
const EventMitter = require("events");
const fs = require("fs");
class ReadStream extends EventMitter {
constructor(path, options = {}) {
super();
this.path = path;
//操作
this.flags = options.flags || "r";
this.encoding = options.encoding || null;
this.autoClose = options.autoClose || true;
this.start = options.start || 0;
this.end = options.end || Infinity; //讀取的個(gè)數(shù),包后的,如果是1 ,就可能讀取到0,1,2
this.highWaterMark = options.highWaterMark || 64 * 1024;
this.emitClose = options.emitClose || false;
this.offset = this.start; // 每次讀取文件的位移數(shù)
this.flowing = true; //暫停繼續(xù)開(kāi)關(guān)
this.open(); // 文件操作,注意這個(gè)方法是異步的。
// events可以監(jiān)聽(tīng)newListener,可以獲取注冊(cè)的所有事件
this.on("newListener", function (type) {
if (type === "data") {
//用戶訂閱了data事件,才去讀取。
this.read(); //這時(shí)候文件還沒(méi)open,fd為undefined。
}
});
}
pause() {
//暫停
this.flowing = false;
}
resume() {
//繼續(xù)
if (!this.flowing) {
this.flowing = true;
this.read();
}
}
destory(err) {
if (err) {
this.emit("error", err);
}
if (this.autoClose) {
fs.close(this.fd, () = {
this.emit("close");
});
}
}
read() {
//希望在open之后打開(kāi)
if (typeof this.fd !== "number") {
this.once("open", (fd) = {
//之前實(shí)現(xiàn)的copy這段邏輯是寫(xiě)在了fs.open里面,換成發(fā)布訂閱模式之后就可以分離出來(lái)。
this.read(); //第二次read的時(shí)候,fd有值了
});
} else {
//判斷每次讀取多少。因?yàn)閠his.end是包后的,比如start = 0, end = 1, 那么讀取的就是 0 , 1, 2所以需要+1
const howMutchToRead = Math.min(
this.end - this.offset + 1,
this.highWaterMark
);
const buffer = Buffer.alloc(howMutchToRead);
fs.read(
this.fd,
buffer,
0,
howMutchToRead,
this.offset,
(err, byteRead) = {
if (err) {
this.destory(err);
} else {
if (byteRead) {
//讀取到文件,發(fā)布data事件,發(fā)送真正讀取到的內(nèi)容
this.offset += byteRead;
this.emit("data", buffer.slice(0, byteRead));
this.flowing this.read();
} else {
this.emit("end");
if (this.autoClose) {
this.destory();
}
}
}
}
);
}
}
open() {
fs.open(this.path, this.flags, (err, fd) = {
if (err) {
//報(bào)錯(cuò):
this.destory(err);
}
//從回調(diào)的形式變成了發(fā)布訂閱模式
this.fd = fd;
this.emit("open", fd);
});
}
}
const rs = new ReadStream("./a.txt", {
flags: "r", //創(chuàng)建可讀流。
encoding: null, //默認(rèn)Buffer
autoClose: true, //自動(dòng)關(guān)閉,相當(dāng)于讀取完畢調(diào)用fs.close
emitClose: true, //觸發(fā)close事件
start: 0, //從文件哪里開(kāi)始讀取
highWaterMark: 3, //每次讀取的數(shù)據(jù)個(gè)數(shù),默認(rèn)是64*1025字節(jié)。
//end: 4, // 比如這個(gè)就會(huì)讀取 1到5的內(nèi)容
});
rs.on("open", () = {
console.log("文件打開(kāi)了");
});
// rs.on("data", (data) = {
// console.log("監(jiān)聽(tīng)Data事件", data);
// });
// //底層還是 fs.open fs.read fs.close
// const rs = fs.createReadStream("./a.txt", {
// flags: "r", //創(chuàng)建可讀流。
// encoding: null, //默認(rèn)Buffer
// autoClose: true, //自動(dòng)關(guān)閉,相當(dāng)于讀取完畢調(diào)用fs.close
// emitClose: true, //觸發(fā)close事件
// start: 0, //從文件哪里開(kāi)始讀取
// highWaterMark: 3, //每次讀取的數(shù)據(jù)個(gè)數(shù),默認(rèn)是64*1025字節(jié)。
// }); //返回一個(gè)對(duì)象
//沒(méi)監(jiān)聽(tīng)前,是非流動(dòng)模式,監(jiān)聽(tīng)后,是流動(dòng)模式。
//監(jiān)聽(tīng)data事件,并且不停觸發(fā)
rs.on("data", function (chunk) {
console.log(chunk);
//暫停
rs.pause();
});
rs.on("end", function () {
console.log("讀取完畢");
});
rs.on("close", function () {
console.log("文件關(guān)閉");
});
setInterval(() = {
console.log("一秒后");
rs.resume();
}, 1000)
前端模板引擎有哪些的介紹就聊到這里吧,感謝你花時(shí)間閱讀本站內(nèi)容,更多關(guān)于前端模板引擎一般用來(lái)開(kāi)發(fā)什么、前端模板引擎有哪些的信息別忘了在本站進(jìn)行查找喔。
掃描二維碼推送至手機(jī)訪問(wèn)。
版權(quán)聲明:本文由飛速云SEO網(wǎng)絡(luò)優(yōu)化推廣發(fā)布,如需轉(zhuǎn)載請(qǐng)注明出處。