Node的簡介

来源:https://www.cnblogs.com/z937741304/archive/2018/08/14/9471904.html
-Advertisement-
Play Games

從開始學習node到現在已經有半年多了,中間沒有做過什麼實際工作中的項目,所以感覺自己的知識有些匱乏,但是我還是要寫這些文章,因為工作中的需要用node來開發後臺環境,再加上我對這些知識記得不多,都是來看以前寫的源碼抄過來,自己根本記不住一些繁瑣的代碼,想藉此機會來鞏固一下我所學到的東西,等以後慢慢 ...


  從開始學習node到現在已經有半年多了,中間沒有做過什麼實際工作中的項目,所以感覺自己的知識有些匱乏,但是我還是要寫這些文章,因為工作中的需要用node來開發後臺環境,再加上我對這些知識記得不多,都是來看以前寫的源碼抄過來,自己根本記不住一些繁瑣的代碼,想藉此機會來鞏固一下我所學到的東西,等以後慢慢來補充我現在所寫的文章。

  可以去百度node.js中文網,上面所寫的第一句話就是這麼一句概括了node.js所有的話吧。

  node.js是一個基於Chorme V8引擎的javascript運行環境。node.js使用了一個事件驅動,非阻塞式I/O模型,使其輕量又高效。

 

 什麼是Chorme V8引擎,它是怎麼來的?此處直達廖雪峰大佬的文章

  Node.js是目前非常火熱的技術,但是它的誕生經歷卻很奇特。

  眾所周知,在Netscape設計出JavaScript後的短短幾個月,JavaScript事實上已經是前端開發的唯一標準。

後來,微軟通過IE擊敗了Netscape後一統桌面,結果幾年時間,瀏覽器毫無進步。(2001年推出的古老的IE 6到今天仍然有人在使用!)

沒有競爭就沒有發展。微軟認為IE6瀏覽器已經非常完善,幾乎沒有可改進之處,然後解散了IE6開發團隊!而Google卻認為支持現代Web應用的新一代瀏覽器才剛剛起步,尤其是瀏覽器負責運行JavaScript的引擎性能還可提升10倍。

先是Mozilla藉助已壯烈犧牲的Netscape遺產在2002年推出了Firefox瀏覽器,緊接著Apple於2003年在開源的KHTML瀏覽器的基礎上推出了WebKit內核的Safari瀏覽器,不過僅限於Mac平臺。

  隨後,Google也開始創建自家的瀏覽器。他們也看中了WebKit內核,於是基於WebKit內核推出了Chrome瀏覽器。

Chrome瀏覽器是跨Windows和Mac平臺的,並且,Google認為要運行現代Web應用,瀏覽器必須有一個性能非常強勁的JavaScript引擎,於是Google自己開發了一個高性能JavaScript引擎,名字叫V8,以BSD許可證開源。

現代瀏覽器大戰讓微軟的IE瀏覽器遠遠地落後了,因為他們解散了最有經驗、戰鬥力最強的瀏覽器團隊!回過頭再追趕卻發現,支持HTML5的WebKit已經成為手機端的標準了,IE瀏覽器從此與主流移動端設備絕緣。

瀏覽器大戰和Node有何關係?

  話說有個叫Ryan Dahl的歪果仁,他的工作是用C/C++寫高性能Web服務。對於高性能,非同步IO、事件驅動是基本原則,但是用C/C++寫就太痛苦了。於是這位仁兄開始設想用高級語言開發Web服務。他評估了很多種高級語言,發現很多語言雖然同時提供了同步IO和非同步IO,但是開發人員一旦用了同步IO,他們就再也懶得寫非同步IO了,所以,最終,Ryan瞄向了JavaScript。

  因為JavaScript是單線程執行,根本不能進行同步IO操作,所以,JavaScript的這一“缺陷”導致了它只能使用非同步IO。

選定了開發語言,還要有運行時引擎。這位仁兄曾考慮過自己寫一個,不過明智地放棄了,因為V8就是開源的JavaScript引擎。讓Google投資去優化V8,咱只負責改造一下拿來用,還不用付錢,這個買賣很划算。

  於是在2009年,Ryan正式推出了基於JavaScript語言和V8引擎的開源Web伺服器項目,命名為Node.js。雖然名字很土,但是,Node第一次把JavaScript帶入到後端伺服器開發,加上世界上已經有無數的JavaScript開發人員,所以Node一下子就火了起來。

在Node上運行的JavaScript相比其他後端開發語言有何優勢?

  最大的優勢是藉助JavaScript天生的事件驅動機制加V8高性能引擎,使編寫高性能Web服務輕而易舉。

  其次,JavaScript語言本身是完善的函數式語言,在前端開發時,開發人員往往寫得比較隨意,讓人感覺JavaScript就是個“玩具語言”。但是,在Node環境下,通過模塊化的JavaScript代碼,加上函數式編程,並且無需考慮瀏覽器相容性問題,直接使用最新的ECMAScript 6標準,可以完全滿足工程上的需求。

 

  node是啥?

  傳統意義上的javascript運行在瀏覽器上,這是因為瀏覽器內核實際上分為兩個部分,渲染引擎和javaScript引擎。前者主要負責渲染HTML+CSS,後者主要負責運行javaScript。Chorme使用的javascript引擎是V8,它的運行速度非常快。

  

  node 跟 chorme 有什麼區別?

  架構一樣,都是基於事件驅動的非同步架構!

  瀏覽器主要是通過事件驅動來服務頁面交互。

  

  node 主要是通過事件驅動來服務 I/O

  node 沒有HTML,WebKit和顯卡等等的UI技術支持

 

  為什麼要用node.js?

  總的來說,Node.js 適合以下場景:

  1. 實時性應用,比如線上多人協作工具,網頁聊天應用等。
  2. 以 I/O 為主的高併發應用,比如為客戶端提供 API,讀取資料庫。
  3. 流式應用,比如客戶端經常上傳文件。
  4. 前後端分離。

  實際上前兩者可以歸結為一種,即客戶端廣泛使用長連接,雖然併發數較高,但其中大部分是空閑連接。

  Node.js 也有它的局限性,它並不適合 CPU 密集型的任務,比如人工智慧方面的計算,視頻、圖片的處理等。

當然,以上缺點不是信口開河,或者死記硬背,更不是人云亦云,需要我們對 Node.js 的原理有一定的瞭解,才能做出正確的判斷。

   

  基礎概念

  併發 下麵的這些是參考的他人的文章

  與客戶端不同,服務端開發者非常關心的一項數據是併發數,也就是這台伺服器最多能支持多少個客戶端的併發請求。早年的 C10K 問題就是討論如何利用單台伺服器支持 10K 併發數。當然隨著軟硬體性能的提高,目前 C10K 已經不再是問題,我們開始嘗試解決 C10M 問題,即單台伺服器如何處理百萬級的併發。

  在 C10K 提出時,我們還在使用 Apache 伺服器,它的工作原理是每當有一個網路請求到達,就 fork 出一個子進程併在子進程中運行 PHP 腳本。執行完腳本後再把結果發回客戶端。

  這樣可以確保不同進程之間互不幹擾,即使一個進程出問題也不影響整個伺服器,但是缺點也很明顯:進程是一個比較重的概念,擁有自己的堆和棧,占用記憶體較多,一臺伺服器能運行的進程數量有上限,大約也就在幾千左右。

雖然 Apache 後來使用了 FastCGI,但本質上只是一個進程池,它減少了創建進程的開銷,但無法有效提高併發數。

  Java 的 Servlet 使用了線程池,即每個 Servlet 運行在一個線程上。線程雖然比進程輕量,但也是相對的。 有人測試過 ,每個線程獨享的棧的大小是 1M,依然不夠高效。除此以外,多線程編程會帶來各種麻煩,這一點想必程式員們都深有體會。

  如果不使用線程,還有兩種解決方案,分別是使用協程(coroutine)和非阻塞 I/O。協程比線程更加輕量,多個協程可以運行在同一個線程中,並由程式員自己負責調度,這種技術在 Go 語言中被廣泛使用。而非阻塞 I/O 則被 Node.js 用來處理高併發的場景。

  

  非阻塞 I/O

  這裡所說的 I/O 可以分為兩種: 網路 I/O 和文件 I/O,實際上兩者高度類似。 I/O 可以分為兩個步驟,首先把文件(網路)中的內容拷貝到緩衝區,這個緩衝區位於操作系統獨占的記憶體區域中。隨後再把緩衝區中的內容拷貝到用戶程式的記憶體區域中。

  對於阻塞 I/O 來說,從發起讀請求,到緩衝區就緒,再到用戶進程獲取數據,這兩個步驟都是阻塞的。

  非阻塞 I/O 實際上是向內核輪詢,緩衝區是否就緒,如果沒有則繼續執行其他操作。當緩衝區就緒時,講緩衝區內容拷貝到用戶進程,這一步實際上還是阻塞的。

I/O 多路復用技術是指利用單個線程處理多個網路 I/O,我們常說的 select 、 epoll 就是用來輪詢所有 socket 的函數。比如 Apache 採用了前者,而 Nginx 和 Node.js 使用了後者,區別在於後者效率更高。由於 I/O 多路復用實際上還是單線程的輪詢,因此它也是一種非阻塞 I/O 的方案。

  非同步 I/O 是最理想的 I/O 模型,然而可惜的是真正的非同步 I/O 並不存在。 Linux 上的 AIO 通過信號和回調來傳遞數據,但是存在缺陷。現有的 libeio 以及 Windows 上的 IOCP,本質上都是利用線程池與阻塞 I/O 來模擬非同步 I/O。

  Node.js 線程模型

很多文章都提到 Node.js 是單線程的,然而這樣的說法並不嚴謹,甚至可以說很不負責,因為我們至少會想到以下幾個問題:

  1. Node.js 在一個線程中如何處理併發請求?
  2. Node.js 在一個線程中如何進行文件的非同步 I/O?
  3. Node.js 如何重覆利用伺服器上的多個 CPU 的處理能力?

  

  網路 I/O

  Node.js 確實可以在單線程中處理大量的併發請求,但這需要一定的編程技巧。總之,在利用 Node.js 編程時,任何耗時操作一定要使用非同步來完成,避免阻塞當前函數。因為你在為客戶端提供服務,而所有代碼總是單線程、順序執行。

 

  文件 I/O

  我在之前的文章中也強調過,非同步是為了優化體驗,避免卡頓。而真正節省處理時間,利用 CPU 多核性能,還是要靠多線程並行處理。

  實際上 Node.js 在底層維護了一個線程池。之前在基礎概念部分也提到過,不存在真正的非同步文件 I/O,通常是通過線程池來模擬。線程池中預設有四個線程,用來進行文件 I/O。

  需要註意的是,我們無法直接操作底層的線程池,實際上也不需要關心它們的存在。線程池的作用僅僅是完成 I/O 操作,而非用來執行 CPU 密集型的操作,比如圖像、視頻處理,大規模計算等。

  如果有少量 CPU 密集型的任務需要處理,我們可以啟動多個 Node.js 進程並利用 IPC 機制進行進程間通訊,或者調用外部的 C++/Java 程式。如果有大量 CPU 密集型任務,那隻能說明選擇 Node.js 是一個錯誤的決定。

  事件迴圈

  在 Node.js 中存在一個事件迴圈(Event Loop)。

  一次完整的 Event Loop 也可以分為多個階段(phase),依次是 poll、check、close callbacks、timers、I/O callbacks 、Idle。

由於 Node.js 是事件驅動的,每個事件的回調函數會被註冊到 Event Loop 的不同階段。比如 fs.readFile 的回調函數被添加到 I/O callbacks, setImmediate 的回調被添加到下一次 Loop 的 poll 階段結束後, process.nextTick() 的回調被添加到當前 phase 結束後,下一個 phase 開始前。

  不同非同步方法的回調會在不同的 phase 被執行,掌握這一點很重要,否則就會因為調用順序問題產生邏輯錯誤。

  Event Loop 不斷的迴圈,每一個階段內都會同步執行所有在該階段註冊的回調函數。這也正是為什麼我在網路 I/O 部分提到,不要在回調函數中調用阻塞方法,總是用非同步的思想來進行耗時操作。一個耗時太久的回調函數可能會讓 Event Loop 卡在某個階段很久,新來的網路請求就無法被及時響應。

由於本文的目的是對 Node.js 有一個初步的,全面的認識。就不詳細介紹 Event Loop 的每個階段了。

  數據流

  使用數據流的好處很明顯,生活中也有真實寫照。舉個例子,老師佈置了暑假作業,如果學生每天都做一點(作業流),就可以比較輕鬆的完成任務。如果積壓在一起,到了最後一天,面對堆成小山的作業本,就會感到力不從心。

  Server 開發也是這樣,假設用戶上傳 1G 文件,或者讀取本地 1G 的文件。如果沒有數據流的概念,我們需要開闢 1G 大小的緩衝區,然後在緩衝區滿後一次性集中處理。

如果是採用數據流的方式,我們可以定義很小的一塊緩衝區,比如大小是 1Mb。當緩衝區滿後就執行回調函數,對這一小塊數據進行處理,從而避免出現積壓。

實際上 request 和 fs 模塊的文件讀取都是一個可讀數據流:

  總結

  對於高併發的長連接,事件驅動模型比線程輕量得多,多個 Node.js 進程配合負載均衡可以方便的進行拓展。因此 Node.js 非常適合為 I/O 密集型應用提供服務。但這種方式的缺陷就是不擅長處理 CPU 密集型任務。

   本來這次是想自己寫一篇文章看看的,但是看到他人寫的文章太好了~~~

  對不起,這次的文章後半部分都是參考的他人的文章

  參考文章: 為什麼要用node.js

          廖雪峰的javaScript教程

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一. 概述 在sql server 備份與恢復系列的第一篇里,有講到大容量模式下備份與還原的相關知識。這篇重點來演示在大容量模式下常用的備份與還原模式“完整備份+差異備份+日誌備份”。 在大容量恢復模式下,特別要註意的是在什麼情況下會導致數據還原丟失風險,帶著這個問題,來進行演示說明。備份策略如下圖 ...
  • 線上上進行DDL操作時,相對於其可能帶來的系統負載,其實,我們最擔心的還是MDL其可能導致的阻塞問題。 一旦DDL操作因獲取不到MDL被阻塞,後續其它針對該表的其它操作都會被阻塞。典型如下,如阻塞稍久的話,我們會看到Threads_running飆升,CPU告警。 如果發生線上上,無疑會影響到業務。 ...
  • 眾所周知,MongoDB包括社區版和企業版,但不止如此,MongoDB公司還有MongoDB Atlas:Database as a Service. MongoDB Atlas delivers the world’s leading database for modern application ...
  • APK文件只能包含一個AndroidManifest.xml文件,但Android Studio項目可以包含多個文件(通過buildSrc、導入的庫引入)。因此,在構建應用時,Gradle構建會將所有清單文件合併到一個封裝的APK的清單文件中。 清單文件合併優先順序 清單合併工具 可以使用Merged ...
  • 至最新的Android P, Google已經提供了世界絕大多數語言的支持。但是對許多發往海外的項目,可能還是會有一些國家的語言google預設沒有支持。下麵將介紹下對於某一特定語言如何判斷Google是否支持這種語言、如何添加一種語言(如果google預設沒有支持)。 還有,自Android N以 ...
  • 安卓逆向(一) Smali基礎 標簽(空格分隔): 安卓逆向 APK的組成 |文件夾|作用| |: |: | |asset文件夾|資源目錄1:asset和res都是資源目錄但有所區別,見下麵說明| |lib文件夾|so庫存放位置,一般由NDK編譯得到,常見於使用游戲引擎或JNI native調用的工 ...
  • import UIKit extension UIImage { /// 獲取網路圖片尺寸 /// /// - Parameter url: 網路圖片鏈接 /// - Returns: 圖片尺寸size class func getImageSize(_ url: String?) -> CGSiz ...
  • Hello 大家好!又要跟大家見面了,上次實在太無聊了,就在博客園跟大家講述了本人職業生涯以來的一些工作經歷,同時也分享了一些工作上的心得,沒想到引起那麼多朋友的共鳴,也鼓舞了很多初入職場的朋友和有相同經歷的朋友,在這裡真的很感謝博客園提供這麼好的平臺,可以讓每一位園友盡情傾吐。 這次我是分享我本人 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...