溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

javascript開(kāi)發(fā)后端程序的神器nodejs的使用方法

發(fā)布時(shí)間:2021-09-30 09:58:52 來(lái)源:億速云 閱讀:124 作者:柒染 欄目:編程語(yǔ)言

本篇文章給大家分享的是有關(guān)javascript開(kāi)發(fā)后端程序的神器nodejs的使用方法,小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話(huà)不多說(shuō),跟著小編一起來(lái)看看吧。

簡(jiǎn)介

javascript雖然一直都可以做服務(wù)端編程語(yǔ)言,但是它更多的是以客戶(hù)端編程語(yǔ)言來(lái)展示在世人面前的。也許javascript自己都忘記了還可以做服務(wù)器端編程,直到2009年nodejs的橫空出世。

nodejs的歷史

javascript作為一門(mén)解釋性語(yǔ)言,是不需要像C或者C++那樣進(jìn)行編譯的。但是在早期的時(shí)候,javascript引擎的執(zhí)行效率是比較低的,所以導(dǎo)致javascript只能做做dom操作。

隨著ajax的興起和現(xiàn)代web2.0的技術(shù)的發(fā)展,主流瀏覽器開(kāi)發(fā)商盡可能的提升javascript的執(zhí)行效率,最后Chrome V8出現(xiàn)了,Chrome V8是 Chromium 項(xiàng)目開(kāi)源的 JavaScript 引擎,使得javascript的執(zhí)行效率得到了極大的提升。

nodejs借著V8浴火重生了。

nodejs從一誕生就獲得了極大的關(guān)注。比較javascript的開(kāi)發(fā)者還是非常非常多的。而且一門(mén)語(yǔ)言可以通用前后端是多么的有吸引力。

nodejs從2009年發(fā)展到2020年的nodejs 14,經(jīng)歷了11年的歷史,和它的先輩javascript相比還是很年輕,但是因?yàn)槠溟_(kāi)放性和包容性,nodejs在以一個(gè)非??斓乃俣认蚯鞍l(fā)展。

nodejs簡(jiǎn)介

nodejs借助于V8引擎和一組異步的 I/O 原生功能,極大的提升了nodejs的處理效率。

異步IO我們大家應(yīng)該都很清楚,和同步IO相比,線(xiàn)程不用阻塞,可以去處理其他更有意義的事情。只是在響應(yīng)返回的時(shí)候恢復(fù)操作,所以不會(huì)浪費(fèi)CPU時(shí)間。

我們簡(jiǎn)單看一下nodejs的IO模型:

javascript開(kāi)發(fā)后端程序的神器nodejs的使用方法

一個(gè)好的語(yǔ)言需要有良好的生態(tài)系統(tǒng)相配合,因?yàn)檎Z(yǔ)言本身只能提供最基本的一些操作,我們還需要第三方系統(tǒng)來(lái)豐富這個(gè)語(yǔ)言的生態(tài)。

而nodejs的npm倉(cāng)庫(kù),托管著全球最大的開(kāi)源庫(kù)生態(tài)系統(tǒng)。

基本上使用nodejs你可以實(shí)現(xiàn)絕大多數(shù)需要的功能。

nodejs的另外一個(gè)特點(diǎn)就是簡(jiǎn)單,考慮一下我們最常用的web應(yīng)用,如果用java來(lái)寫(xiě),非常麻煩,你還需要一個(gè)web服務(wù)器。

在nodejs中,一切都是那么的簡(jiǎn)單:

const http = require('http')

const hostname = '127.0.0.1'
const port = 3000

const server = http.createServer((req, res) => {
 res.statusCode = 200
 res.setHeader('Content-Type', 'text/plain')
 res.end('welcome to www.flydean.com\n')
})

server.listen(port, hostname, () => {
 console.log(`please visit http://${hostname}:${port}/`)
})

上面的代碼就創(chuàng)建了一個(gè)web服務(wù),監(jiān)聽(tīng)在3000端口,

我們首先引入了http模塊,用來(lái)進(jìn)行http處理。

接著使用http 的 createServer() 方法會(huì)創(chuàng)建新的 HTTP 服務(wù)器并返回它。

在createServer方法內(nèi)部,我們可以設(shè)定要返回的對(duì)象。

最后啟用server.listen功能,來(lái)監(jiān)聽(tīng)特定的端口和服務(wù)器,當(dāng)服務(wù)就緒之后,會(huì)調(diào)用后面的回調(diào)函數(shù),執(zhí)行特定的命令。

每當(dāng)接收到新的請(qǐng)求的時(shí)候,就會(huì)觸發(fā)request事件,request事件可以傳遞兩個(gè)參數(shù):

  • request 是一個(gè)http.IncomingMessage對(duì)象,提供了請(qǐng)求的詳細(xì)信息。

  • response 是一個(gè)http.ServerResponse對(duì)象,用于返回?cái)?shù)據(jù)給調(diào)用方。

在上面的例子中,我們并沒(méi)有使用request,而是使用response直接構(gòu)建了返回的對(duì)象。

我們?cè)O(shè)置了statusCode和header,最后使用end來(lái)關(guān)閉響應(yīng)。

這就是一個(gè)簡(jiǎn)單使用的nodejs程序。

nodejs的運(yùn)行環(huán)境

nodejs作為js的一種,是一種解釋性語(yǔ)言,一般解釋性語(yǔ)言都有兩種運(yùn)行方式。

一種是直接運(yùn)行,一種是開(kāi)啟一個(gè)解釋性的環(huán)境,在其中運(yùn)行,nodejs也不例外。

直接運(yùn)行很簡(jiǎn)單,我們寫(xiě)好nodejs的程序之后,比如app.js,直接這樣運(yùn)行:

node app.js

如果直接執(zhí)行node命令,就會(huì)開(kāi)啟REPL模式:

node
Welcome to Node.js v12.13.1.
Type ".help" for more information.
>

REPL 也被稱(chēng)為運(yùn)行評(píng)估打印循環(huán),是一種編程語(yǔ)言環(huán)境(主要是控制臺(tái)窗口),它使用單個(gè)表達(dá)式作為用戶(hù)輸入,并在執(zhí)行后將結(jié)果返回到控制臺(tái)。

REPL有什么作用呢?

第一,我們可以直接在REPL中運(yùn)行某些測(cè)試方法,已驗(yàn)證輸出結(jié)果。

比如這樣:

> console.log('www.flydean.com');
www.flydean.com

除此之外REPL還有一些更加有用的功能,我們知道JS中一切皆對(duì)象,比如上面我們提到的http對(duì)象,如果我們想知道http對(duì)象的大概結(jié)構(gòu)怎么辦呢?

直接在REPL環(huán)境中輸入http即可:

> http
{
 _connectionListener: [Function: connectionListener],
 METHODS: [
   'ACL',         'BIND',       'CHECKOUT',
   'CONNECT',     'COPY',       'DELETE',
   'GET',         'HEAD',       'LINK',
   'LOCK',        'M-SEARCH',   'MERGE',
   'MKACTIVITY',  'MKCALENDAR', 'MKCOL',
   'MOVE',        'NOTIFY',     'OPTIONS',
   'PATCH',       'POST',       'PROPFIND',
   'PROPPATCH',   'PURGE',      'PUT',
   'REBIND',      'REPORT',     'SEARCH',
   'SOURCE',      'SUBSCRIBE',  'TRACE',
   'UNBIND',      'UNLINK',     'UNLOCK',
   'UNSUBSCRIBE'
 ],
 STATUS_CODES: {
   '100': 'Continue',
   '101': 'Switching Protocols',
   '102': 'Processing',
   '103': 'Early Hints',
   '200': 'OK',
   '201': 'Created',
   '202': 'Accepted',
   '203': 'Non-Authoritative Information',
   '204': 'No Content',
   '205': 'Reset Content',
   '206': 'Partial Content',
   '207': 'Multi-Status',
   '208': 'Already Reported',
   '226': 'IM Used',
   '300': 'Multiple Choices',
   '301': 'Moved Permanently',
   '302': 'Found',
   '303': 'See Other',
   '304': 'Not Modified',
   '305': 'Use Proxy',
   '307': 'Temporary Redirect',
   '308': 'Permanent Redirect',
   '400': 'Bad Request',
   '401': 'Unauthorized',
   '402': 'Payment Required',
   '403': 'Forbidden',
   '404': 'Not Found',
   '405': 'Method Not Allowed',
   '406': 'Not Acceptable',
   '407': 'Proxy Authentication Required',
   '408': 'Request Timeout',
   '409': 'Conflict',
   '410': 'Gone',
   '411': 'Length Required',
   '412': 'Precondition Failed',
   '413': 'Payload Too Large',
   '414': 'URI Too Long',
   '415': 'Unsupported Media Type',
   '416': 'Range Not Satisfiable',
   '417': 'Expectation Failed',
   '418': "I'm a Teapot",
   '421': 'Misdirected Request',
   '422': 'Unprocessable Entity',
   '423': 'Locked',
   '424': 'Failed Dependency',
   '425': 'Unordered Collection',
   '426': 'Upgrade Required',
   '428': 'Precondition Required',
   '429': 'Too Many Requests',
   '431': 'Request Header Fields Too Large',
   '451': 'Unavailable For Legal Reasons',
   '500': 'Internal Server Error',
   '501': 'Not Implemented',
   '502': 'Bad Gateway',
   '503': 'Service Unavailable',
   '504': 'Gateway Timeout',
   '505': 'HTTP Version Not Supported',
   '506': 'Variant Also Negotiates',
   '507': 'Insufficient Storage',
   '508': 'Loop Detected',
   '509': 'Bandwidth Limit Exceeded',
   '510': 'Not Extended',
   '511': 'Network Authentication Required'
 },
 Agent: [Function: Agent] { defaultMaxSockets: Infinity },
 ClientRequest: [Function: ClientRequest],
 IncomingMessage: [Function: IncomingMessage],
 OutgoingMessage: [Function: OutgoingMessage],
 Server: [Function: Server],
 ServerResponse: [Function: ServerResponse],
 createServer: [Function: createServer],
 get: [Function: get],
 request: [Function: request],
 maxHeaderSize: [Getter],
 globalAgent: [Getter/Setter]
}

直接輸出了http對(duì)象的簡(jiǎn)潔結(jié)構(gòu),我們還可以使用tab按鈕來(lái)自動(dòng)補(bǔ)全http的方法:

> http.
http.__defineGetter__      http.__defineSetter__      http.__lookupGetter__      http.__lookupSetter__      http.__proto__             http.constructor
http.hasOwnProperty        http.isPrototypeOf         http.propertyIsEnumerable  http.toLocaleString        http.toString              http.valueOf

http.Agent                 http.ClientRequest         http.IncomingMessage       http.METHODS               http.OutgoingMessage       http.STATUS_CODES
http.Server                http.ServerResponse        http._connectionListener   http.createServer          http.get                   http.globalAgent
http.maxHeaderSize         http.request

PREL還支持一些特定的點(diǎn)操作:

> .help
.break    Sometimes you get stuck, this gets you out
.clear    Alias for .break
.editor   Enter editor mode
.exit     Exit the repl
.help     Print this help message
.load     Load JS from a file into the REPL session
.save     Save all evaluated commands in this REPL session to a file

PERL還有一個(gè)特殊變量 _ ,如果在某些代碼之后輸入 _,則會(huì)打印最后一次操作的結(jié)果。

process

process 對(duì)象是一個(gè)全局變量,提供了有關(guān)當(dāng)前 Node.js 進(jìn)程的信息并對(duì)其進(jìn)行控制。作為全局變量,它始終可供 Node.js 應(yīng)用程序使用,無(wú)需使用 require()。它也可以使用 require() 顯式地訪(fǎng)問(wèn)。

因?yàn)閜rocess代表的是nodejs的進(jìn)程信息,所以可以處理進(jìn)程終止,讀取環(huán)境變量,接收命令行參數(shù)等作用。

終止進(jìn)程

先看一下怎么使用process來(lái)終止進(jìn)程:

process.exit(0)

0表示正常退出,當(dāng)然,我們可以傳入不同的退出碼,表示不同的含義。

正常情況下,如果沒(méi)有異步操作正在等待,那么 Node.js 會(huì)以狀態(tài)碼 0 退出,其他情況下,會(huì)用如下的狀態(tài)碼:

1 未捕獲異常 – 一個(gè)未被捕獲的異常, 并且沒(méi)被 domain 或 ‘uncaughtException’ 事件處理器處理。

2 – 未被使用 (Bash 為防內(nèi)部濫用而保留)

3 內(nèi)部的 JavaScript 解析錯(cuò)誤 – Node.js 內(nèi)部的 JavaScript 源代碼在引導(dǎo)進(jìn)程中導(dǎo)致了一個(gè)語(yǔ)法解析錯(cuò)誤。一般只會(huì)在開(kāi)發(fā) Node.js 本身的時(shí)候出現(xiàn)。

4 內(nèi)部的 JavaScript 執(zhí)行失敗 – 引導(dǎo)進(jìn)程執(zhí)行 Node.js 內(nèi)部的 JavaScript 源代碼時(shí),返回函數(shù)值失敗。一般只會(huì)在開(kāi)發(fā) Node.js 本身的時(shí)候出現(xiàn)。

5 致命錯(cuò)誤 – 在 V8 中有一個(gè)致命的錯(cuò)誤。比較典型的是以 FATALERROR 為前綴從 stderr 打印出來(lái)的消息。

6 非函數(shù)的內(nèi)部異常處理 – 發(fā)生了一個(gè)內(nèi)部異常,但是內(nèi)部異常處理函數(shù)被設(shè)置成了一個(gè)非函數(shù),或者不能被調(diào)用。

7 內(nèi)部異常處理運(yùn)行時(shí)失敗 – 有一個(gè)不能被捕獲的異常,在試圖處理這個(gè)異常時(shí),處理函數(shù)本身拋出了一個(gè)錯(cuò)誤。比如, 如果一個(gè) ‘uncaughtException’ 或者 domain.on(‘error’) 處理函數(shù)拋出了一個(gè)錯(cuò)誤。

8 – 未被使用,在之前版本的 Node.js, 退出碼 8 有時(shí)候表示一個(gè)未被捕獲的異常。

9 – 不可用參數(shù) – 某個(gè)未知選項(xiàng)沒(méi)有確定,或者沒(méi)給必需要的選項(xiàng)填值。

10 內(nèi)部的 JavaScript 運(yùn)行時(shí)失敗 – 調(diào)用引導(dǎo)函數(shù)時(shí),引導(dǎo)進(jìn)程執(zhí)行 Node.js 內(nèi)部的 JavaScript 源代碼拋出錯(cuò)誤。一般只會(huì)在開(kāi)發(fā) Node.js 本身的時(shí)候出現(xiàn)。

12 不可用的調(diào)試參數(shù)

13 未完成的Top-Level Await: await傳入的Promise一直沒(méi)有調(diào)用resolve方法

128 退出信號(hào) – 如果 Node.js 接收到致命信號(hào), 諸如 SIGKILL 或 SIGHUP,那么它的退出代碼將是 128 加上信號(hào)的碼值。例如,信號(hào) SIGABRT 的值為 6,因此預(yù)期的退出代碼將為 128 + 6 或 134。

我們可以通過(guò)process的on方法,來(lái)監(jiān)聽(tīng)信號(hào)事件:

process.on('SIGTERM', () => {
 server.close(() => {
   console.log('進(jìn)程已終止')
 })
})

什么是信號(hào)?信號(hào)是一個(gè) POSIX 內(nèi)部通信系統(tǒng):發(fā)送通知給進(jìn)程,以告知其發(fā)生的事件。

或者我們可以從程序內(nèi)部發(fā)送這個(gè)信號(hào):

process.kill(process.pid, 'SIGTERM')

env

因?yàn)閜rocess進(jìn)程是和外部環(huán)境打交道的,process提供了env屬性,該屬性承載了在啟動(dòng)進(jìn)程時(shí)設(shè)置的所有環(huán)境變量。

默認(rèn)情況下,env中的NODE_ENV被設(shè)置為development。

process.env.NODE_ENV // "development"

我們可以通過(guò)修改這個(gè)環(huán)境變量,來(lái)切換nodejs的不同運(yùn)行環(huán)境。

argv

process提供了argv來(lái)接收外部參數(shù)。

比如:

node app.js joe

argv是一個(gè)包含所有命令行調(diào)用參數(shù)的數(shù)組。

上面的例子中,第一個(gè)參數(shù)是 node 命令的完整路徑。第二個(gè)參數(shù)是正被執(zhí)行的文件的完整路徑。所有其他的參數(shù)從第三個(gè)位置開(kāi)始。

要想獲取joe,我們可以這樣做:

const args = process.argv.slice(2)
args[0]

如果是key=value的情況,我們可以這樣傳參數(shù),并且使用minimist 庫(kù)來(lái)處理參數(shù):

node app.js --name=joe

const args = require('minimist')(process.argv.slice(2))
args['name'] //joe

CLI交互

從 nodejs7開(kāi)始,nodejs提供了readline模塊,可以從process.stdin獲取輸入:

const readline = require('readline').createInterface({
 input: process.stdin,
 output: process.stdout
})

readline.question(`how are you?`, answer => {
 console.log(`${answer}!`)
 readline.close()
})

如果需要更加復(fù)雜的操作,則可以使用Inquirer.js:

const inquirer = require('inquirer')

var questions = [
 {
   type: 'input',
   name: 'hello',
   message: "how are you?"
 }
]

inquirer.prompt(questions).then(answers => {
 console.log(`${answers['hello']}!`)
})

exports模塊

nodejs擁有內(nèi)置的模塊系統(tǒng),當(dāng)我們需要使用其他lib提供的功能時(shí)候,我們可以使用require來(lái)引入其他lib公開(kāi)的模塊。

但是前提是該lib需要公開(kāi),也就是exports對(duì)應(yīng)的模塊出來(lái)。

nodejs的對(duì)象導(dǎo)出有兩種方式module.exports和將對(duì)象添加為 exports 的屬性。

先看第一種方式,square 模塊定義在 square.js 中:

module.exports = class Square {
 constructor(width) {
   this.width = width;
 }

 area() {
   return this.width ** 2;
 }
};

下面的例子中, bar.js 使用了導(dǎo)出 Square 類(lèi)的 square 模塊:

const Square = require('./square.js');
const mySquare = new Square(2);
console.log(`mySquare 的面積是 ${mySquare.area()}`);

再看第二種方式,定義一個(gè)circle.js:

const { PI } = Math;

exports.area = (r) => PI * r ** 2;

exports.circumference = (r) => 2 * PI * r;

使用:

const circle = require('./circle.js');
console.log(`半徑為 4 的圓的面積是 ${circle.area(4)}`);

兩者都可以導(dǎo)出特定的模塊,但是module.exports只會(huì)導(dǎo)出特定的對(duì)象,而exports是將對(duì)象添加為exports的屬性,我們還需要根據(jù)屬性名稱(chēng)來(lái)查找對(duì)象的屬性。

nodejs API

除了我們上面提到的http,process, nodejs還提供了很多其他非常有用的API :

javascript開(kāi)發(fā)后端程序的神器nodejs的使用方法

nodejs的框架

除了基本的nodejs之外,nodejs還有非常多優(yōu)秀的框架,借助這些框架我們可以是nodejs程序的搭建更加容易和強(qiáng)大。

像AdonisJs,express,koa,Socket.io等等。

以上就是javascript開(kāi)發(fā)后端程序的神器nodejs的使用方法,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見(jiàn)到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI