久久精品五月,日韩不卡视频在线观看,国产精品videossex久久发布 ,久久av综合

站長資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

nodejs有哪十大常見錯誤

node的十大常見錯誤:1、阻塞事件循環(huán);2、多次調用一個回調函數(shù);3、深層嵌套的回調函數(shù);4、期待回調函數(shù)同步執(zhí)行;5、給“exports”賦值;6、從回調里拋出錯誤;7、認為Number是一種整型數(shù)據(jù)格式;8、忽略流式API的優(yōu)勢等等。

nodejs有哪十大常見錯誤

本教程操作環(huán)境:windows7系統(tǒng)、nodejs 12.19.0版,DELL G3電腦。

自 Node.js 面世以來,它獲得了大量的贊美和批判。這種爭論會一直持續(xù),短時間內都不會結束。而在這些爭論中,我們常常會忽略掉所有語言和平臺都是基于一些核心問題來批判的,就是我們怎么去使用這些平臺。無論使用 Node.js 編寫可靠的代碼有多難,而編寫高并發(fā)代碼又是多么的簡單,這個平臺終究是有那么一段時間了,而且被用來創(chuàng)建了大量的健壯而又復雜的 web 服務。這些 web 服務不僅擁有良好的擴展性,而且通過在互聯(lián)網(wǎng)上持續(xù)的時間證明了它們的健壯性。

然而就像其它平臺一樣,Node.js 很容易令開發(fā)者犯錯。這些錯誤有些會降低程序性能,有些則會導致 Node.js 不可用。在本文中,我們會看到 Node.js 新手常犯的 十種錯誤,以及如何去避免它們。

錯誤1:阻塞事件循環(huán)

Node.js(正如瀏覽器)里的 JavaScript 提供了一種單線程環(huán)境。這意味著你的程序不會有兩塊東西同時在運行,取而代之的是異步處理 I/O 密集操作所帶來的并發(fā)。比如說 Node.js 給數(shù)據(jù)庫發(fā)起一個請求去獲取一些數(shù)據(jù)時,Node.js 可以集中精力在程序的其他地方:

// Trying to fetch an user object from the database. Node.js is free to run other parts of the code from the moment this function is invoked..	 db.User.get(userId, function(err, user) {	     // .. until the moment the user object has been retrieved here	 })

然而,在一個有上千個客戶端連接的 Node.js 實例里,一小段 CPU 計算密集的代碼會阻塞住事件循環(huán),導致所有客戶端都得等待。CPU 計算密集型代碼包括了嘗試排序一個巨大的數(shù)組、跑一個耗時很長的函數(shù)等等。例如:

function sortUsersByAge(users) {	     users.sort(function(a, b) {	         return a.age < b.age ? -1 : 1	     })	 }

在一個小的“users” 數(shù)組上調用“sortUsersByAge” 方法是沒有任何問題的,但如果是在一個大數(shù)組上,它會對整體性能造成巨大的影響。如果這種事情不得不做,而且你能確保事件循環(huán)上沒有其他事件在等待(比如這只是一個 Node.js 命令行工具,而且它不在乎所有事情都是同步工作的)的話,那這沒有問題。但是,在一個 Node.js 服務器試圖給上千用戶同時提供服務的情況下,它就會引發(fā)問題。

如果這個 users 數(shù)組是從數(shù)據(jù)庫獲取的,那么理想的解決方案是從數(shù)據(jù)庫里拿出已排好序的數(shù)據(jù)。如果事件循環(huán)被一個計算金融交易數(shù)據(jù)歷史總和的循環(huán)所阻塞,這個計算循環(huán)應該被推到事件循環(huán)外的隊列中執(zhí)行以免占用事件循環(huán)。

正如你所見,解決這類錯誤沒有銀彈,只有針對每種情況單獨解決。基本理念是不要在處理客戶端并發(fā)連接的 Node.js 實例上做 CPU 計算密集型工作。

錯誤2:多次調用一個回調函數(shù)

一直以來 JavaScript 都依賴于回調函數(shù)。在瀏覽器里,事件都是通過傳遞事件對象的引用給一個回調函數(shù)(通常都是匿名函數(shù))來處理。在 Node.js 里,回調函數(shù)曾經是與其他代碼異步通信的唯一方式,直到 promise 出現(xiàn)。回調函數(shù)現(xiàn)在仍在使用,而且很多開發(fā)者依然圍繞著它來設置他們的 API。一個跟使用回調函數(shù)相關的常見錯誤是多次調用它們。通常,一個封裝了一些異步處理的方法,它的最后一個參數(shù)會被設計為傳遞一個函數(shù),這個函數(shù)會在異步處理完后被調用:

module.exports.verifyPassword = function(user, password, done) {	     if(typeof password !== ‘string’) {	         done(new Error(‘password should be a string’))	         return	     }	     computeHash(password, user.passwordHashOpts, function(err, hash) {	         if(err) {	             done(err)	             return	         }	         done(null, hash === user.passwordHash)	     })	 }

注意到除了最后一次,每次“done” 方法被調用之后都會有一個 return 語句。這是因為調用回調函數(shù)不會自動結束當前方法的執(zhí)行。如果我們注釋掉第一個 return 語句,然后傳一個非字符串類型的 password 給這個函數(shù),我們依然會以調用 computeHash 方法結束。根據(jù) computeHash 在這種情況下的處理方式,“done” 函數(shù)會被調用多次。當傳過去的回調函數(shù)被多次調用時,任何人都會被弄得措手不及。

避免這個問題只需要小心點即可。一些 Node.js 開發(fā)者因此養(yǎng)成了一個習慣,在所有調用回調函數(shù)的語句前加一個 return 關鍵詞:

if(err) {	     return done(err)	 }

在很多異步函數(shù)里,這種 return 的返回值都是沒有意義的,所以這種舉動只是為了簡單地避免這個錯誤而已。

錯誤3:深層嵌套的回調函數(shù)

深層嵌套的回調函數(shù)通常被譽為“ 回調地獄”,它本身并不是什么問題,但是它會導致代碼很快變得失控:

function handleLogin(..., done) {	     db.User.get(..., function(..., user) {	         if(!user) {	             return done(null, ‘failed to log in’)	         }	         utils.verifyPassword(..., function(..., okay) {	             if(okay) {	                 return done(null, ‘failed to log in’)	             }	             session.login(..., function() {	                 done(null, ‘logged in’)	             })	         })	     })	 }

越復雜的任務,這個的壞處就越大。像這樣嵌套回調函數(shù),我們的程序很容易出錯,而且代碼難以閱讀和維護。一個權宜之計是把這些任務聲明為一個個的小函數(shù),然后再將它們聯(lián)系起來。不過,(有可能是)最簡便的解決方法之一是使用一個 Node.js 公共組件來處理這種異步 js,比如 Async.js:

function handleLogin(done) {	     async.waterfall([	         function(done) {	             db.User.get(..., done)	         },	         function(user, done) {	             if(!user) {	             return done(null, ‘failed to log in’)	             }	             utils.verifyPassword(..., function(..., okay) {	                 done(null, user, okay)	             })	         },	         function(user, okay, done) {	             if(okay) {	                 return done(null, ‘failed to log in’)	             }	             session.login(..., function() {	                 done(null, ‘logged in’)	             })	         }	     ], function() {	         // ...	     })	 }

Async.js 還提供了很多類似“async.waterfall” 的方法去處理不同的異步場景。為了簡便起見,這里我們演示了一個簡單的示例,實際情況往往復雜得多。

(打個廣告,隔壁的《ES6 Generator 介紹》提及的 Generator 也是可以解決回調地獄的哦,而且結合 Promise 使用更加自然,請期待隔壁樓主的下篇文章吧:D)

錯誤4:期待回調函數(shù)同步執(zhí)行

使用回調函數(shù)的異步程序不只是 JavaScript 和 Node.js 有,只是它們讓這種異步程序變得流行起來。在其他編程語言里,我們習慣了兩個語句一個接一個執(zhí)行,除非兩個語句之間有特殊的跳轉指令。即使那樣,這些還受限于條件語句、循環(huán)語句以及函數(shù)調用。

然而在 JavaScript 里,一個帶有回調函數(shù)的方法直到回調完成之前可能都無法完成任務。當前函數(shù)會一直執(zhí)行到底:

function testTimeout() {	     console.log(“Begin”)	     setTimeout(function() {	         console.log(“Done!”)	     }, duration * 1000)	     console.log(“Waiting..”)	 }

你可能會注意到,調用“testTimeout” 函數(shù)會先輸出“Begin”,然后輸出“Waiting..”,緊接著幾秒后輸出“Done!”。

任何要在回調函數(shù)執(zhí)行完后才執(zhí)行的代碼,都需要在回調函數(shù)里調用。

錯誤5:給“exports” 賦值,而不是“module.exports”

Node.js 認為每個文件都是一個獨立的模塊。如果你的包有兩個文件,假設是“a.js” 和“b.js”,然后“b.js” 要使用“a.js” 的功能,“a.js” 必須要通過給 exports 對象增加屬性來暴露這些功能:

// a.js	 exports.verifyPassword = function(user, password, done) { ... }

完成這步后,所有需要“a.js” 的都會獲得一個帶有“verifyPassword” 函數(shù)屬性的對象:

// b.js	 require(‘a.js’) // { verifyPassword: function(user, password, done) { ... } }

然而,如果我們想直接暴露這個函數(shù),而不是讓它作為某些對象的屬性呢?我們可以覆寫 exports 來達到目的,但是我們絕對不能把它當做一個全局變量:

// a.js	 module.exports = function(user, password, done) { ... }

注意到我們是把“exports” 當做 module 對象的一個屬性。“module.exports” 和“exports” 這之間區(qū)別是很重要的,而且經常會使 Node.js 新手踩坑。

錯誤6:從回調里拋出錯誤

JavaScript 有異常的概念。在語法上,學絕大多數(shù)傳統(tǒng)語言(如 Java、C++)對異常的處理那樣,JavaScript 可以拋出異常以及在 try-catch 語句塊中捕獲異常:

function slugifyUsername(username) {	     if(typeof username === ‘string’) {	         throw new TypeError(‘expected a string username, got '+(typeof username))	     }	     // ...	 }	 try {	     var usernameSlug = slugifyUsername(username)	 } catch(e) {	     console.log(‘Oh no!’)	 }

然而,在異步環(huán)境下,tary-catch 可能不會像你所想的那樣。比如說,如果你想用一個大的 try-catch 去保護一大段含有許多異步處理的代碼,它可能不會正常的工作:

try {	     db.User.get(userId, function(err, user) {	         if(err) {	             throw err	         }	         // ...	         usernameSlug = slugifyUsername(user.username)	         // ...	     })	 } catch(e) {	     console.log(‘Oh no!’)	 }

如果“db.User.get” 的回調函數(shù)異步執(zhí)行了,那么 try-catch 原來所在的作用域就很難捕獲到回調函數(shù)里拋出的異常了。

這就是為什么在 Node.js 里通常使用不同的方式處理錯誤,而且這使得所有回調函數(shù)的參數(shù)都需要遵循 (err, …) 這種形式,其中第一個參數(shù)是錯誤發(fā)生時的 error 對象。

錯誤7:認為 Number 是一種整型數(shù)據(jù)格式

在 JavaScript 里數(shù)字都是浮點型,沒有整型的數(shù)據(jù)格式。你可能認為這不是什么問題,因為數(shù)字大到溢出浮點型限制的情況很少出現(xiàn)。可實際上,當這種情況發(fā)生時就會出錯。因為浮點數(shù)在表達一個整型數(shù)時只能表示到一個最大上限值,在計算中超過這個最大值時就會出問題。也許看起來有些奇怪,但在 Node.js 中下面代碼的值是 true:

Math.pow(2, 53)+1 === Math.pow(2, 53)

很不幸的是,JavaScript 里有關數(shù)字的怪癖可還不止這些。盡管數(shù)字是浮點型的,但如下這種整數(shù)運算能正常工作:

5 % 2 === 1 // true	 5 >> 1 === 2 // true

然而和算術運算不同的是,位運算和移位運算只在小于 32 位最大值的數(shù)字上正常工作。例如,讓“Math.pow(2, 53)” 位移 1 位總是得到 0,讓其與 1 做位運算也總是得到 0:

Math.pow(2, 53) / 2 === Math.pow(2, 52) // true	 Math.pow(2, 53) >> 1 === 0 // true	 Math.pow(2, 53) | 1 === 0 // true

你可能極少會去處理如此大的數(shù)字,但如果你需要的話,有很多實現(xiàn)了大型精密數(shù)字運算的大整數(shù)庫可以幫到你,比如 node-bigint。

錯誤8:忽略了流式 API 的優(yōu)勢

現(xiàn)在我們想創(chuàng)建一個簡單的類代理 web 服務器,它能通過拉取其他 web 服務器的內容來響應和發(fā)起請求。作為例子,我們創(chuàng)建一個小型 web 服務器為 Gravatar 的圖像服務。

var http = require('http')	 var crypto = require('crypto')	 http.createServer()	 .on('request', function(req, res) {	     var email = req.url.substr(req.url.lastIndexOf('/')+1)	     if(!email) {	         res.writeHead(404)	         return res.end()	     }	     var buf = new Buffer(1024*1024)	     http.get('http://www.gravatar.com/avatar/'+crypto.createHash('md5').update(email).digest('hex'), function(resp) {	         var size = 0	         resp.on('data', function(chunk) {	             chunk.copy(buf, size)	             size += chunk.length	         })	         .on('end', function() {	             res.write(buf.slice(0, size))	             res.end()	         })	     })	 })	 .listen(8080)

在這個例子里,我們從 Gravatar 拉取圖片,將它存進一個 Buffer 里,然后響應請求。如果 Gravatar 的圖片都不是很大的話,這樣做沒問題。但想象下如果我們代理的內容大小有上千兆的話,更好的處理方式是下面這樣:

http.createServer()	 .on('request', function(req, res) {	     var email = req.url.substr(req.url.lastIndexOf('/')+1)	     if(!email) {	         res.writeHead(404)	         return res.end()	     }	     http.get('http://www.gravatar.com/avatar/'+crypto.createHash('md5').update(email).digest('hex'), function(resp) {	         resp.pipe(res)	     })	 })	 .listen(8080)

這里我們只是拉取圖片然后簡單地以管道方式響應給客戶端,而不需要在響應它之前讀取完整的數(shù)據(jù)存入緩存。

錯誤9:出于 Debug 的目的使用 Console.log

在 Node.js 里,“console.log” 允許你打印任何東西到控制臺上。比如傳一個對象給它,它會以 JavaScript 對象的字符形式打印出來。它能接收任意多個的參數(shù)并將它們以空格作為分隔符打印出來。有很多的理由可以解釋為什么開發(fā)者喜歡使用它來 debug 他的代碼,然而我強烈建議你不要在實時代碼里使用“console.log”。你應該要避免在所有代碼里使用“console.log” 去 debug,而且應該在不需要它們的時候把它們注釋掉。你可以使用一種專門做這種事的庫代替,比如 debug。

這些庫提供了便利的方式讓你在啟動程序的時候開啟或關閉具體的 debug 模式,例如,使用 debug 的話,你能夠阻止任何 debug 方法輸出信息到終端上,只要不設置 DEBUG 環(huán)境變量即可。使用它十分簡單:

// app.js	 var debug = require(‘debug’)(‘app’)	 debug(’Hello, %s!’, ‘world’)

開啟 debug 模式只需簡單地運行下面的代碼把環(huán)境變量 DEBUG 設置到“app” 或“*” 上:

DEBUG=app node app.js

錯誤10:不使用監(jiān)控程序

不管你的 Node.js 代碼是跑在生產環(huán)境或是你的本地開發(fā)環(huán)境,一個能協(xié)調你程序的監(jiān)控程序是十分值得擁有的。一條經常被開發(fā)者提及的,針對現(xiàn)代程序設計和開發(fā)的建議是你的代碼應該有 fail-fast 機制。如果發(fā)生了一個意料之外的錯誤,不要嘗試去處理它,而應該讓你的程序崩潰然后讓監(jiān)控程序在幾秒之內重啟它。監(jiān)控程序的好處不只是重啟崩潰的程序,這些工具還能讓你在程序文件發(fā)生改變的時候重啟它,就像崩潰重啟那樣。這讓開發(fā) Node.js 程序變成了一個更加輕松愉快的體驗。

Node.js 有太多的監(jiān)控程序可以使用了,例如:

pm2

forever

nodemon

supervisor

所有這些工具都有它的優(yōu)缺點。一些擅長于在一臺機器上處理多個應用程序,而另一些擅長于日志管理。不管怎樣,如果你想開始寫一個程序,這些都是不錯的選擇。

總結

你可以看到,這其中的一些錯誤能給你的程序造成破壞性的影響,在你嘗試使用 Node.js 實現(xiàn)一些很簡單的功能時一些錯誤也可能會導致你受挫。即使 Node.js 已經使得新手上手十分簡單,但它依然有些地方容易讓人混亂。從其他語言過來的開發(fā)者可能已知道了這其中某些錯誤,但在 Node.js 新手里這些錯誤都是很常見的。幸運的是,它們都可以很容易地避免。我希望這個簡短指南能幫助新手更好地編寫 Node.js 代碼,而且能夠給我們大家開發(fā)出健壯高效的軟件。

贊(0)
分享到: 更多 (0)
?
網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號
久久精品五月,日韩不卡视频在线观看,国产精品videossex久久发布 ,久久av综合
少妇精品久久久| 日韩免费高清| 久久都是精品| 亚洲青青久久| 国产精品视频一区二区三区综合| 国产美女精品视频免费播放软件| 久久精品 人人爱| 久久99国产精品视频| 日韩1区2区| 激情综合网站| 最新亚洲国产| 国产精品久久久久久久久久久久久久久| 国产精品高清一区二区| 91综合视频| 日韩视频久久| 亚洲一区二区日韩| 国产人成精品一区二区三| 国产91欧美| 日韩午夜高潮| 国产激情欧美| 欧美日韩一区二区三区四区在线观看 | 国产成人精品999在线观看| 成人综合一区| 国产真实久久| 日韩高清不卡在线| 国产suv精品一区二区四区视频| 九九综合在线| 国产精品www994| 亚洲国产日韩欧美在线| 欧美日韩亚洲国产精品| 亚洲va中文在线播放免费| 免费不卡在线观看| 国产a亚洲精品| 在线一区二区三区视频| 国产精品麻豆久久| 日韩中文字幕亚洲一区二区va在线| 日本成人中文字幕| av综合电影网站| 日本欧美在线看| 在线视频精品| 精品久久电影| 日本不卡高清视频| 99久久亚洲精品| 国产精品nxnn| 亚洲无线观看| 久久久噜噜噜| 国产精品日韩精品在线播放| 合欧美一区二区三区| 美女久久久久久| 香蕉久久一区| 午夜国产欧美理论在线播放| 欧美日本二区| 亚洲激情av| 高清av一区| 中文字幕免费一区二区| 视频二区不卡| 欧美极品一区二区三区| 亚洲欧美久久久| av高清不卡| 卡一卡二国产精品| 日韩欧美久久| 制服诱惑一区二区| 日本成人一区二区| 中文日韩在线| 日韩专区精品| 麻豆精品视频在线| 男人的天堂亚洲一区| 91综合久久爱com| 中文亚洲免费| 国精品一区二区三区| 国产精品伦理久久久久久| 国产精品22p| 青青草伊人久久| 亚洲精品伊人| 亚洲一区二区三区久久久| 99xxxx成人网| 国产一区成人| 亚洲精品网址| av一区二区高清| 999久久久精品国产| 卡一精品卡二卡三网站乱码| 日韩欧美美女在线观看| 亚洲综合激情在线| 一区二区三区四区在线观看国产日韩| 午夜久久免费观看| 欧美日韩一区二区三区视频播放| 成人国产精品久久| 国产一区二区三区久久久久久久久| 久久国内精品视频| 欧美日韩一区二区高清| 日韩黄色在线观看| 日韩在线成人| 日日摸夜夜添夜夜添国产精品| 亚洲一区国产| 亚洲欧美高清| 亚洲三级精品| 日韩中文字幕麻豆| 日本不卡视频在线| 日本vs亚洲vs韩国一区三区二区| 亚洲人成高清| 欧美亚洲免费| 久久精品av麻豆的观看方式| 国产乱码精品一区二区三区亚洲人 | 婷婷精品久久久久久久久久不卡| 亚洲青青久久| 国产精品最新| 国产精品成人一区二区不卡| 午夜久久中文| 亚洲精品一二三区区别| 国产亚洲网站| 日本麻豆一区二区三区视频| 国产精品国码视频| 特黄毛片在线观看| 最新国产拍偷乱拍精品| 亚洲综合图色| 久久国产麻豆精品| 国产成人精品福利| 宅男在线一区| 亚洲精品自拍| 九九99久久精品在免费线bt| 精品亚洲美女网站| 国产视频一区免费看| 少妇精品久久久一区二区| 久久不卡日韩美女| 97精品国产| 亚洲精品极品少妇16p| 天堂va欧美ⅴa亚洲va一国产| 国产精品videossex| 久久国产日韩| 亚洲三级在线| av资源新版天堂在线| 亚洲免费观看| 国产福利资源一区| 蜜桃成人av| 国产亚洲精品美女久久 | 午夜精品福利影院| 欧美精品导航| 欧美午夜精彩| 日韩av网站在线观看| 正在播放日韩精品| 蜜桃av一区二区| а√天堂8资源中文在线| 国产精品免费看| 国产伊人久久| 一区二区三区国产在线| 日韩伦理福利| 97精品国产99久久久久久免费| 日韩av免费大片| 一区二区精彩视频| 鲁鲁在线中文| 日韩av午夜在线观看| 午夜精品久久久久久久久久蜜桃| 一区二区精品| 久久婷婷亚洲| 麻豆久久久久久| 一区二区三区午夜视频| 国产成人精品亚洲日本在线观看| 日韩有吗在线观看| 国产精品7m凸凹视频分类| 国产精成人品2018| 在线精品国产亚洲| 久久精品中文| 久久99久久久精品欧美| 亚洲一区二区三区高清不卡| 日本久久综合| 国产精品自在| 视频一区视频二区在线观看| 中文字幕一区久| 国产极品一区| 欧美一区二区三区久久| 国产精品日韩久久久| 国产v日韩v欧美v| 国产精品多人| 日韩高清国产一区在线| 久久成人一区| 欧美高清不卡| 91视频精品| 国产精品白丝久久av网站| 中文字幕av一区二区三区人| 欧美福利在线| 久久国产中文字幕| 国产传媒av在线| 国产剧情在线观看一区| 日韩综合小视频| 日韩精品一级二级| av不卡免费看| 亚洲香蕉网站| 福利在线免费视频| 久久香蕉网站| 国产精品嫩模av在线| 亚洲精品亚洲人成在线观看| 黄色成人精品网站| 久久在线视频免费观看| 精品99在线| 美女视频黄免费的久久| 91九色综合| 欧美精品国产| 91福利精品在线观看| 亚洲精品免费观看| 综合一区二区三区|