2万人同时访问 nodejs_面向前端工程师的Nodejs入门手册(一)
前言
本文面向的讀者已經(jīng)是了解JavaScript基本使用的前端程序員,但是缺乏服務(wù)端的經(jīng)驗(yàn),接下來(lái)將帶你走進(jìn)在服務(wù)端的世界,看看運(yùn)行在服務(wù)端的JavaScript是如何工作的,它與運(yùn)行在瀏覽器端的JavaScript有何異同,相比于瀏覽器能多做哪些事情,有何優(yōu)勢(shì)。
文章通過(guò)實(shí)例的方式,讓你了解Nodejs能夠做什么,可以解決一些什么樣的問(wèn)題,并且知道它的使用場(chǎng)景。如果你有興趣,請(qǐng)記住一定要自己動(dòng)手,哪怕照著實(shí)例寫(xiě)一遍,真真實(shí)實(shí)的感受代碼運(yùn)行時(shí)的喜悅與興奮,激發(fā)自己對(duì)新領(lǐng)域的興趣。
默認(rèn)你已經(jīng)安裝了Nodejs和npm包管理器,并且熟悉一些簡(jiǎn)單的操作,如nodejs代碼的運(yùn)行啟動(dòng),npm包的安裝命令等基礎(chǔ)操作。
第一個(gè)服務(wù)端應(yīng)用
1.hello world?
首先通過(guò)一個(gè)前端工程師最常接觸卻不屬于前端范疇的內(nèi)容去了解一下Nodejs,創(chuàng)建一個(gè)http服務(wù)。這里使用Nodejs自帶的http模塊創(chuàng)建一個(gè)http服務(wù),你可以使用通過(guò)瀏覽器或者命令行來(lái)發(fā)起一個(gè)http請(qǐng)求,直觀(guān)的感受服務(wù)端的JavaScript。
// http.jsconst http = require('http');http.createServer((req, res) => { res.end('Hello World!');}).listen(8000, ()=> { console.log('listen on 8000!');})上面的例子中,通過(guò)使用node自帶的http模塊,調(diào)用其http.creatServer方法在本機(jī)上開(kāi)啟了一個(gè)http服務(wù),監(jiān)聽(tīng)了本地的8000端口,代碼邏輯很簡(jiǎn)單,當(dāng)接收到一個(gè)req請(qǐng)求時(shí),調(diào)用res.end返回一個(gè)字符串"hello world"給帶客戶(hù)端,旨在讓你對(duì)Nodejs有一個(gè)直觀(guān)的體驗(yàn)。
可以使用node http.js命令來(lái)執(zhí)行這段代碼,通過(guò)瀏覽器來(lái)訪(fǎng)問(wèn)http://127.0.0.1:8000或者h(yuǎn)ttp://localhost:800來(lái)查看結(jié)果。
一個(gè)由Nodejs的http服務(wù)提供的hello world跑起來(lái)了,簡(jiǎn)潔快速吧。接下來(lái)再來(lái)實(shí)現(xiàn)一個(gè)前端工作中與服務(wù)端最緊密的內(nèi)容來(lái)看看Nodejs的魅力,數(shù)據(jù)接口。
2. 如何提供一個(gè)API?
首先這里確定所要提供的api是我們最常用的json格式,所以我們要注意后端返回給前端的數(shù)據(jù)類(lèi)型。
const http = require('http');const data = { name: 'Nodejs 入門(mén)示例', description: '這是返回信息的描述內(nèi)容', date: new Date()};http.createServer((req, res) => { res.setHeader('Content-Type', 'application/json;charset=utf-8'); const result = JSON.stringify(data); res.end(result);}).listen(8000, ()=> { console.log('listen on 8000!');})上例子中,先確定了一個(gè)數(shù)據(jù)模型data,內(nèi)部一共有三個(gè)字段。這里的數(shù)據(jù)模型就是前端開(kāi)發(fā)前與后端所定義的返回格式,最終前端要拿到這個(gè)JSON格式的數(shù)據(jù)在客戶(hù)端進(jìn)行處理。代碼邏輯相比于Hello World,規(guī)定了返回的數(shù)據(jù)格式,以及設(shè)定了返回請(qǐng)求的文本類(lèi)型為application/json,然后調(diào)用res.end返回到客戶(hù)端。
可以繼續(xù)使用瀏覽器發(fā)起http請(qǐng)求來(lái)查看結(jié)果,一個(gè)簡(jiǎn)單且熟悉的JSON數(shù)據(jù)接口已經(jīng)完成了。你可以按照前端最常用的調(diào)用方式,如ajax或者axios來(lái)請(qǐng)求接口來(lái)在你的前端項(xiàng)目使用它。
但是上面例子中的接口和我們常用的接口有一個(gè)差異點(diǎn),就是接口名稱(chēng)和返回內(nèi)容均不規(guī)范,使用者直接通過(guò)沒(méi)有路徑的http://127.0.0.1:8000來(lái)使用接口,這跟我們?nèi)粘J褂玫慕涌谑峭耆灰粯拥?#xff0c;那我們接下來(lái)再看一下如何給提供一個(gè)規(guī)范化的接口呢?
3.一個(gè)規(guī)范的接口
規(guī)范的接口具備哪些條件呢?簡(jiǎn)單總結(jié)一下。
接口名稱(chēng):接口名稱(chēng)要體現(xiàn)出大致的使用場(chǎng)景,例如增刪改查的動(dòng)作。
接口返回:接口返回要有規(guī)范化的標(biāo)識(shí),如成功與否錯(cuò)誤內(nèi)容等。
接下來(lái)通過(guò)上面這兩個(gè)點(diǎn),按照標(biāo)準(zhǔn)的接口規(guī)范來(lái)實(shí)現(xiàn)一下上面的接口,看看Nodejs是如何給前端提供接口的。這里先約定要提供的接口名稱(chēng)內(nèi)含api標(biāo)志,api所要做的動(dòng)作等一些關(guān)鍵信息。如下格式:
http://localhost:8000/api/search/data?userId=12345
const http = require('http');const url = require('url');const qs = require('querystring');// 生成一段返回值const genResponse = userId => ({ success: true, data: { userId, name: 'Nodejs 入門(mén)示例', description: '這是返回信息的描述內(nèi)容', date: new Date() }});// http服務(wù)http.createServer((req, res) => { res.setHeader('Content-Type', 'application/json;charset=utf-8'); const reqUrl = url.parse(req.url);??// 判斷接口路徑是否是約定好的 if (reqUrl.pathname === '/api/search/data') {????//?獲取鏈接上傳來(lái)的userId參數(shù) const uid = qs.parse(reqUrl.query).userId; // 生成返回值 const result = JSON.stringify(genResponse(uid)); res.end(result); } else { res.writeHeader(404); res.end('NotFund'); }}).listen(8000, ()=> { console.log('listen on 8000!');})上面的例子中,新使用Nodejs另一個(gè)自帶的模塊url,url模塊顧名思義是一個(gè)處理href的庫(kù),它將href拆分成各個(gè)子內(nèi)容,同時(shí)為了能處理客戶(hù)端帶來(lái)的userId參數(shù)還使用了自帶的querystring模塊,它可以將鏈接上問(wèn)號(hào)后的query參數(shù)獲取到,以便服務(wù)端代碼能使用他們,他們均屬于工具庫(kù),下面看看官方對(duì)于URL模塊將href拆分的顆粒度圖,清晰的了解一下一個(gè)請(qǐng)求鏈接,可以被拆分成什么顆粒度。
實(shí)例中的源碼簡(jiǎn)單解析一下,當(dāng)服務(wù)接收到請(qǐng)求時(shí),先判斷請(qǐng)求的api名稱(chēng)是不是事先約定好的/api/search/data,判斷通過(guò)后,將前端傳遞在鏈接上的參數(shù)userId獲取到,處理后插入到返回的json數(shù)據(jù)中,即可通過(guò)res.end來(lái)下發(fā)數(shù)據(jù),如果路徑判斷失敗,則返回404的狀態(tài)碼,并且進(jìn)入Notfund頁(yè)面,
一個(gè)規(guī)范的接口已經(jīng)開(kāi)發(fā)完成了,簡(jiǎn)單總結(jié)一下,上面以漸進(jìn)式的方式了解了Nodejs如何給前端來(lái)提供一個(gè)規(guī)范化的http接口,了解了服務(wù)端的JavaScript所具備的能力,接下來(lái)再?gòu)牧硪粋€(gè)前端工程師比較少接觸的內(nèi)容——文件操作,來(lái)進(jìn)一步了解Nodejs。
文件操作那些事
對(duì)于文件操作相關(guān)的內(nèi)容,前端程序員一般是不會(huì)觸及的,而且JavaScript語(yǔ)言本身也并沒(méi)有暴露操作文件的方法。而在Nodejs中,本身便提供了fs文件操作模塊,這個(gè)模塊模塊底層并不是JavaScript來(lái)編寫(xiě)的,是具備操作文件的C++語(yǔ)言編寫(xiě)的,其封裝完成后將上層暴露給Nodejs,然后便可以使用JavaScript的語(yǔ)法來(lái)調(diào)用它。
1.讀一個(gè)文件
在Nodejs中,讀文件有兩種形式,一種是同步的另一種是異步的,同步可以理解為讀文件這個(gè)過(guò)程要等待,就是一旦執(zhí)行的讀這個(gè)操作的時(shí)候,你的代碼就被”卡“住了,直到文件讀完才能繼續(xù)執(zhí)行,來(lái)看看下面的例子。
先新增一個(gè)test.md文件配合讀操作,文件內(nèi)容為:### 我是一個(gè)文件
// fsread.jsconst fs = require('fs');const file = fs.readFileSync('./test.md', 'utf8');console.log(file);// ### 我是一個(gè)文件使用node fsread.js來(lái)運(yùn)行上面的代碼,從上面簡(jiǎn)單的幾行你就可以發(fā)現(xiàn)成功將test.md文件里的內(nèi)容讀出來(lái),可以打印到了命令行console里,突然發(fā)現(xiàn)JavaScript語(yǔ)言的強(qiáng)大了吧,很神奇吧。
但是Nodejs天生是為異步而生的,所以必須要體驗(yàn)一下異步讀文件是怎么的過(guò)程,與同步的表現(xiàn)有何異同。所以?下面示例一個(gè)異步回調(diào)的方式去讀一個(gè)文件,異步的意思就是讀文件這個(gè)操作進(jìn)行的同時(shí),讀操作下面的JavaScript代碼也在執(zhí)行,就如同我們熟悉的軟件后臺(tái)運(yùn)行一樣,你可以繼續(xù)你的桌面操作。
const fs = require('fs');console.log('sync start');fs.readFile('./test.md', 'utf8', (err, data) => { console.log('test.md 的內(nèi)容'); console.log(data);});console.log('sync progress');fs.readFile('./test2.md', 'utf8', (err, data) => { console.log('test2.md 的內(nèi)容'); console.log(data);});console.log('sync finish');在上面的例子中,要求是一次讀取兩個(gè)文件,兩個(gè)文件之間并沒(méi)有相關(guān)依賴(lài)性,所以這種 場(chǎng)景下我們更希望他們各做各的,無(wú)需去等。所以沒(méi)有必要像上面同步的方式,等第一個(gè)結(jié)束再進(jìn)入第二個(gè)的讀取,所以使用異步方式更合適。
從上面的執(zhí)行結(jié)果也可以看出來(lái),fs.readFile這個(gè)異步回調(diào)操作均在三個(gè)同步代碼 console的后面,并沒(méi)有像同步等待讀操作的結(jié)束。
下面來(lái)個(gè)圖看看這個(gè)同步API和異步API有何異同。
圖片上半部分是異步讀文件,可以看出來(lái),讀的操作可以理解為同時(shí)刻執(zhí)行的。
圖片下半部分是同步讀文件,第二個(gè)讀的操作需要先等待第一個(gè)讀完才可以。
舉個(gè)現(xiàn)實(shí)生活中同步的場(chǎng)景,運(yùn)動(dòng)會(huì)接力賽,A,B兩個(gè)班比賽接力,雖然A,B兩個(gè)班無(wú)依賴(lài),但是A班的第二名同學(xué)則需要第一名同學(xué)的接力棒拿到后才可繼續(xù)跑,此時(shí)A班的運(yùn)動(dòng)員之間就屬于同步阻塞類(lèi)型。
在舉個(gè)異步的場(chǎng)景,老板通過(guò)全員會(huì)議下達(dá)了一個(gè)任務(wù),任務(wù)是大家做一百個(gè)俯臥撐,誰(shuí)先做完任務(wù)則可以領(lǐng)取10000元紅包的獎(jiǎng)勵(lì),大家聽(tīng)到后紛紛原地做起,在這時(shí)候各個(gè)員工之間就是異步的,他們各做各的,誰(shuí)先做完就可以執(zhí)行老板給他們的開(kāi)始說(shuō)的領(lǐng)取獎(jiǎng)勵(lì)操作,這個(gè)操作可以理解為異步回調(diào)函數(shù)。
2. 寫(xiě)一個(gè)文件
Nodejs寫(xiě)文件也是有兩個(gè)類(lèi)型,同步與異步,實(shí)際執(zhí)行流程與上面的“讀”是一樣的。
下面進(jìn)入同步讀文件的例子,執(zhí)行下面的代碼你會(huì)發(fā)現(xiàn)多了一個(gè)test3.md文件,并且寫(xiě)入'### 我是測(cè)試文件test3'的內(nèi)容
const?fs?=?require('fs');const body = '### 我是測(cè)試文件test3的內(nèi)容';fs.writeFileSync('./test3.md',?body);再來(lái)看一下異步寫(xiě)一個(gè)文件的例子,做一個(gè)對(duì)比。
// 來(lái)一個(gè)異步的看看。const fs = require('fs');const body = '### 我是測(cè)試文件test4的內(nèi)容';fs.writeFile('./test4.md', body, (err) => { if (err) throw err; console.log('文件test4已被保存');});const body2 = '### 我是測(cè)試文件test5的內(nèi)容';fs.writeFile('./test5.md', body2, (err) => { if (err) throw err; console.log('文件test5已被保存');});這是寫(xiě)文件的結(jié)果,這時(shí)候你的本地會(huì)多出兩個(gè)文件test4.md和test5.md出來(lái)。
3.其他文件操作
其實(shí)Nodejs提供了豐富的文件操作接口,除了讀寫(xiě),還有像復(fù)制,給文件授權(quán),刪除一個(gè)文件,文件夾的操作,文件內(nèi)容的監(jiān)聽(tīng)等,如果你有對(duì)文件的操作需求,請(qǐng)先在文檔查一下看是否能夠滿(mǎn)足你。?
文檔地址:http://nodejs.cn/api/fs.html
下面來(lái)一個(gè)文件內(nèi)容監(jiān)聽(tīng)的例子,帶你看看一個(gè)文件變化時(shí)也能被觀(guān)察到樂(lè)趣。
const fs = require('fs');fs.watch('./test6.md', 'utf8', (eventType, filename)=>{ // eventType 是 'rename' 或 'change', // filename 是觸發(fā)事件的文件的名稱(chēng) console.log('eventType', eventType); console.log('filename', filename);});我將test6.md的內(nèi)容進(jìn)行手動(dòng)的變化,并且改了名字,這里都被監(jiān)聽(tīng)到了,是不是很有趣,跟我一起來(lái)練習(xí)吧。
總結(jié)
本文從前端工程師們最常接觸卻又不屬于前端領(lǐng)域的兩個(gè)方面,http服務(wù)與文件操作展開(kāi)了學(xué)習(xí),從幾個(gè)簡(jiǎn)單易懂的例子帶領(lǐng)去了解了Nodejs。回想當(dāng)初我為什么學(xué)習(xí)Nodejs,其實(shí)就是因?yàn)樗暮?jiǎn)單便捷,幾行代碼就能做出一些我想要的效果,能快速的完成我的要求。
如果上面的入門(mén)示例也讓你對(duì)Nodejs有了濃厚的興趣,那么請(qǐng)快速動(dòng)手學(xué)習(xí)起來(lái)吧,看再多文章不如自己手寫(xiě)一遍,從零到一,跟我一起學(xué)習(xí)吧。
文章用到的代碼均可在此獲取:
https://github.com/FantasyGao/Practice-book/tree/master/nodejs
如上內(nèi)容均為自己總結(jié),難免會(huì)有錯(cuò)誤或者認(rèn)識(shí)偏差,如有問(wèn)題,希望大家留言指正,以免誤人,若有什么問(wèn)題請(qǐng)留言,會(huì)盡力回答之。如果對(duì)你有幫助不要忘了分享給你的朋友或者點(diǎn)擊右下方的“在看”哦!也可以關(guān)注作者,查看歷史文章并且關(guān)注最新動(dòng)態(tài),助你早日成為一名全棧工程師!
總結(jié)
以上是生活随笔為你收集整理的2万人同时访问 nodejs_面向前端工程师的Nodejs入门手册(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: nginx实现ip端口转发_Nginx实
- 下一篇: html里下拉标记,HTML: sele