『壹』 node怎麼實現多線程
一、node單線程實現高並發原理
眾所周知nodejs是單線程且支持高並發的腳本語言。可為什麼單線程的nodejs可以支持高並發呢?很多人都不明白其原理,下面我來談談我的理解:
1. node的優點:I/O密集型處理是node的強項,因為node的I/O請求都是非同步的(如:sql查詢請求、文件流操作操作請求、http請求...)
a. 什麼是非同步?
非同步:發出操作指令,然後就可以去做別的事情了,所有操作完成後再執行回調
非同步的實現原理:
// 第一步:定義變數 let a = 1; // 第二步:發出指令,然後把回調函數加入非同步隊列(回調函數並沒有執行) setTimeout(() => { console.log(a); }, 0) // 第三步:賦值,回調函數沒有執行 a = 2; // 第四步:發出指令,然後把回調函數加入非同步隊列(回調函數並沒有執行) setTimeout(() => { console.log(a); }, 0) // 第五步:賦值,回調函數沒有執行 a = 3; // 當所有代碼執行完畢,cpu空閑下來了,就會開始執行非同步隊列裡面的回調函數 // 所以最後控制台輸出:3 3
b. 什麼是非同步I/O?
非同步I/O顧名思義就是非同步的發出I/O請求
c. 雖然nodejs可以非同步的發出I/O請求,但nodejs不支持多線程,為啥就可以支持高並發呢?
因為nodejs的I/O操作,底層是開啟了多線程的
當同時有多個IO請求時,主線程會創建多個eio線程,以提高IO請求的處理速度
額外知識點:
d. 雖然nodejs的I/O操作開啟了多線程,但是所有線程都是基於主線程開啟的只能跑在一個進程當中還是不能充分利用cpu資源
pm2進程管理器可以解決這個問題
pm2 是一個帶有負載均衡功能的Node應用的進程管理器.
e. cpu核數與線程之間的關系
在過去單CPU時代,單任務在一個時間點只能執行單一程序。之後發展到多任務階段,計算機能在同一時間點並行執行多任務或多進程。雖然並不是真正意義上的「同一時間點」,而是多個任務或進程共享一個CPU,並交由操作系統來完成多任務間對CPU的運行切換,以使得每個任務都有機會獲得一定的時間片運行。而現在多核CPU的情況下,同一時間點可以執行多個任務,具體到這個任務在CPU哪個核上運行,這個就跟操作系統和CPU本身的設計相關了
2. node的缺點:不擅長cpu密集型的操作
a. 什麼是cpu密集型操作(復雜的運算、圖片的操作)
// 這就是一個cpu密集型的操作 for (let i = 0; i < 1000000; i++) { console.log(i); }
b. nodejs為什麼不擅長cpu密集型操作
因為nodejs是單線程的
『貳』 為什麼要用nodejs服務
總的來說,Node.js的應用場景
1) 適合
JSON APIs——構建一個Rest/JSON API服務,Node.js可以充分發揮其非阻塞IO模型以及JavaScript對JSON的功能支持(如JSON.stringfy函數)
單頁面、多Ajax請求應用——如Gmail,前端有大量的非同步請求,需要服務後端有極高的響應速度
基於Node.js開發Unix命令行工具——Node.js可以大量生產子進程,並以流的方式輸出,這使得它非常適合做Unix命令行工具
流式數據——傳統的Web應用,通常會將HTTP請求和響應看成是原子事件。而Node.js會充分利用流式數據這個特點,構建非常酷的應用。如實時文件上傳系統transloadit
准實時應用系統——如聊天系統、微博系統,但Javascript是有垃圾回收機制的,這就意味著,系統的響應時間是不平滑的(GC垃圾回收會導致系統這一時刻停止工作)。如果想要構建硬實時應用系統,Erlang是個不錯的選擇
2) 不適合
CPU使用率較重、IO使用率較輕的應用——如視頻編碼、人工智慧等,Node.js的優勢無法發揮
簡單Web應用——此類應用的特點是,流量低、物理架構簡單,Node.js無法提供像Ruby的Rails或者Python的Django這樣強大的框架
NoSQL + Node.js——如果僅僅是為了追求時髦,且自己對這兩門技術還未深入理解的情況下,不要冒險將業務系統搭建在這兩個漂亮的名詞上,建議使用MySQL之類的傳統資料庫
如果系統可以匹配Node.js的適用場景,那麼是時候採取具體的措施來說服老闆了。
說服自己老闆採用Node.js的方式
構建一個簡單的原型——花一周時間構建系統某一部分的原型是非常值得的,同時也很容易和老闆在某一點達成一致,等到系統真的在某一部分應用了Node.js,就是打開局面的時候
尋找開發者——首先JavaScript語言的普及度很高,一般公司都不乏Web前端工程師,而此類工程師的學習門檻也非常低。這就意味著Node.js很容易招人,或者公司就隱藏了一些高手
強大的社區支持——Node.js社區非常活躍,吸引很多優秀的工程師,這就意味著公司可以很容易從社區得到免費或者付費的支持
系統性能考慮——JavaScript引擎Google V8,加之原生非同步IO模型,使得Node.js在性能的表現非常出色,處理數以千計的並發請求非常輕松
『叄』 node.js可以寫服務端嗎
可以的,Nodejs就是為服務端而生的,說開了NodeJs只是JavaScript作為CommonJS的實現,使得JavaScript在伺服器端有了用武之地,所以NodeJs從語法層面來說還是JavaScript。但是與客戶端的JavaScript又有所區別。注意以下幾點:
要學習NodeJs,必須有一定的JavaScript基礎,理解事件模型,了解JavaScript的語法和特性,理解JavaScript面向對象編程
學習NodeJs類似於Python等代碼組織的方式——包機制,require和exports。
一些基本的操作系統,HTTP等網路通信,資料庫(尤其是非關系資料庫),Web編程的知識有所了解。
具體的你可以訪問NODEJS官網或者訪問國內的社區、博客查詢相關內容
『肆』 Nodejs學習筆記之NET模塊
一,開篇分析
從今天開始,我們來深入具體的模塊學習,這篇文章是這個系列文章的第三篇,前兩篇主要是以理論為主,相信大家在前兩篇的學習中,
對NodeJS也有一個基本的認識,沒事!!!趁熱打鐵,讓我們繼續將NodeJS進行到底,好了廢話不多說,直接進入今天的主題
「Net模塊」
,那麼」Net「應該如何理解那?
它是做什麼用的那?(Net模塊可用於創建Socket伺服器或Socket客戶端。NodeJS
的數據通信,最基礎的兩個模塊是
Net
和
Http,前者是基於
Tcp
的封裝,後者本質還是
Tcp
層,只不過做了比較多的數據封裝,我們視為表現層)。
這里參考一下NodeJS
「http.js」
中的源碼:
從圖中不難看出
HttpServer繼承了Net類,具有了相關的通信能力,做了比較多的數據封裝,我們視為更高級的表現層。
擴展知識(以下是「inherits」的源碼):
復制代碼
代碼如下:
exports.inherits
=
function(ctor,
superCtor)
{
ctor.super_
=
superCtor;
ctor.prototype
=
Object.create(superCtor.prototype,
{
constructor:
{
value:
ctor,
enumerable:
false,
writable:
true,
configurable:
true
}
});
};
功能是實現繼承復用。
剛才做了一個簡要的概述,裡面有一些常用的概念,這里做個簡短的概念普及介紹:
(1),TCP/IP------TPC/IP協議是傳輸層協議,主要解決數據如何在網路中傳輸。
(2),Socket------socket則是對TCP/IP協議的封裝和應用(程序層面)。
(3),Http------HTTP是應用層協議,主要解決如何包裝數據。
(4),網路七層模型------物理層、數據鏈路層、網路層、傳輸層、會話層、表示層和應用層。
總結一下:Socket是對TCP/IP協議的封裝,Socket本身並不是協議,而是一個調用介面(API)。
從而形成了我們知道的一些最基本的函數介面,比如Create、Listen、Connect、Accept、Send、Read和Write等等。
TCP/IP只是一個協議棧,就像操作系統的運行機制一樣,必須要具體實現,同時還要提供對外的操作介面
實際上,傳輸層的TCP是基於網路層的IP協議的,而應用層的HTTP協議又是基於傳輸層的TCP協議的,而Socket本身不算是協議,就像上面所說,它只是提供了一個針對TCP或者UDP編程的介面。
二,體驗一把
好了,概念我們也有了,來個例子:
1,建立server.js
復制代碼
代碼如下:
var
net
=
require('net')
;
var
server
=
net.createServer(function(c)
{
//
Connection監聽器
console.log("伺服器已連接")
;
c.on("end",
function()
{
console.log("伺服器已斷開")
;
})
;
c.write("Hello,Bigbear
!
")
;
c.pipe(c)
;
})
;
server.listen(8124,
function()
{
//
Listening監聽器
console.log("伺服器已綁定")
;
})
;
2,建立client.js
復制代碼
代碼如下:
var
net
=
require('net')
;
var
client
=
net.connect({
port:
8124
},function(){
//
connect監聽器
console.log("客戶端已連接")
;
client.write('Hello,Baby
!
')
;
});
client.on("data",
function(data)
{
console.log(data.toString())
;
client.end()
;
});
client.on("end",
function(){
console.log("客戶端斷開連接")
;
})
;
分析一下:
服務端------net.createServer創建一個
TCP
服務,這個服務綁定(server.listen)在
8124
這個埠上,創建
Server
後我們看到有一個回調函數,
在調用上面函數的時候傳入一個參數,這個參數也是函數,並且接受了
socket
,這個由其他方法構造的一個管道(pipe),他的作用就是用來數據交互的。
pipe
是需要
Client
跟
Server
打招呼才能建立的,如果此刻沒有客戶端訪問
Server,這個
socket
就不會存在了。
客戶端------net.connect顧名思義,就是連接到服務端,第一個參數是對象,設置埠(port)為
8124,也就是我們伺服器監聽的埠,由於沒有設置
host
參數,那默認就是
localhost
(本地)。
在
Server
中,socket
是管道的一端,而在
client
中,client
本身就是管道的一端,如果是多個客戶端連接
Server,Server
會新建多個
socket,每個
socket
對應一個
client。
運行結果:
三,案例引入
(1),下面代碼僅僅是伺服器向客戶端輸出一段文本,完成服務端到客戶端的單向通訊。
復制代碼
代碼如下:
//
Sever
-->
Client
的單向通訊
var
net
=
require('net');
var
chatServer
=
net.createServer();
chatServer.on('connection',
function(client)
{
client.write('Hi!
');
//
服務端向客戶端輸出信息,使用
write()
方法
client.write('Bye!
');
client.end();
//
服務端結束該次會話
});
chatServer.listen(9000);
Telnet測試一下:telnet127.0.0.1:9000
執行
telnet後,與服務點連接,反饋
Hi!
Bye!
的字元,並立刻結束服務端程序終止連接。
如果我們要服務端接到到客戶端的信息?
可以監聽
server.data
事件並且不要中止連接(否則會立刻結束無法接受來自客戶端的消息)。
(2),監聽
server.data
事件並且不要中止連接(否則會立刻結束無法接受來自客戶端的消息)。
復制代碼
代碼如下:
//
在前者的基礎上,實現
Client
-->
Sever
的通訊,如此一來便是雙向通訊
var
net
=
require('net');
var
chatServer
=
net.createServer(),
clientList
=
[];
chatServer.on('connection',
function(client)
{
//
JS
可以為對象自由添加屬性。這里我們添加一個
name
的自定義屬性,用於表示哪個客戶端(客戶端的地址+埠為依據)
client.name
=
client.remoteAddress
+
':'
+
client.remotePort;
client.write('Hi
'
+
client.name
+
'!
');
clientList.push(client);
client.on('data',
function(data)
{
broadcast(data,
client);//
接受來自客戶端的信息
});
});
function
broadcast(message,
client)
{
for(var
i=0;i<clientList.length;i+=1)
{
if(client
!==
clientList[i])
{
clientList[i].write(client.name
+
"
says
"
+
message);
}
}
}
chatServer.listen(9000);
上面是不是一個完整功能的代碼呢?我們說還有一個問題沒有考慮進去:那就是一旦某個客戶端退出,卻仍保留在
clientList裡面,這明顯是一個空指針。
(3),處理clientList
復制代碼
代碼如下:
chatServer.on('connection',
function(client)
{
client.name
=
client.remoteAddress
+
':'
+
client.remotePort
client.write('Hi
'
+
client.name
+
'!
');
clientList.push(client)
client.on('data',
function(data)
{
broadcast(data,
client)
})
client.on('end',
function()
{
clientList.splice(clientList.indexOf(client),
1);
//
刪除數組中的制定元素。
})
})
NodeTCPAPI已經為我們提供了
end
事件,即客戶端中止與服務端連接的時候發生。
(4),優化broadcast
復制代碼
代碼如下:
function
broadcast(message,
client)
{
var
cleanup
=
[]
for(var
i=0;i<clientList.length;i+=1)
{
if(client
!==
clientList[i])
{
if(clientList[i].writable)
{
//
先檢查
sockets
是否可寫
clientList[i].write(client.name
+
"
says
"
+
message)
}
else
{
cleanup.push(clientList[i])
//
如果不可寫,收集起來銷毀。銷毀之前要
Socket.destroy()
用
API
的方法銷毀。
clientList[i].destroy()
}
}
}
//Remove
dead
Nodes
out
of
write
loop
to
avoid
trashing
loop
index
for(i=0;i<cleanup.length;i+=1)
{
clientList.splice(clientList.indexOf(cleanup[i]),
1)
}
}
注意的是一旦
「end」
沒有被觸發,會出現異常,所以才做優化工作。
(5),NetAPI中還提供一個
error
事件,用於捕捉客戶端的異常
復制代碼
代碼如下:
client.on('error',
function(e)
{
console.log(e);
});
四,總結一下
1,理解開篇的相關概念
2,認識Http與Net模塊之間的關系
3,結合本文的例子,查閱相關api去實踐
4,socket客戶端與伺服器端之間的通信思想
5,有興趣可以完善一下那個聊天室的例子
『伍』 web前端開發常用工具有哪些
1、jQuery
jQuery由於其無限的教程,沒有跨平台/瀏覽器問題,優秀的用戶界面,大量的插件以及它的輕量,歲喊快速和快速學習等特點而脫穎而出。超過70%的受訪者選擇jQuery作為他們的前端庫,它是一個快速,輕量級和簡潔的JavaScript庫,主要用於HTML文檔遍歷、事件攜含處理、動畫和用於快速Web開發的Ajax交互。從本質上講,jQuery最適合需要快速開發的應用程序。
2、Bootstrap
超過65%的開發者選擇Bootstrap作為他們最喜歡的框架來使用,它是一個用HTML、CSS和JS開發的開源工具包。Bootstrap的廣泛流行主要是因為它的簡單使用、優秀的社區以及大量的文章和教程、第三方插件和擴展、主題構建器等。
3、Angular
如果你打算構建一個動態且強大的單頁應用程序,Angular就是你需要的框架。Angular是高度模塊化的,因此非常適合與團隊分開大型工作,並且使測試和調試變得輕松。功能優先的方法使Angular更加專注於功能,使開發人員的工作更輕松。此外,它還有來自Google社區的出色工具和支持。
4、NPM
NPM是Node的包管理器。藉助NPM,開發人員可以安裝各種模塊進行Web開發,共享和借用軟體包,並管理私有開發。它由網站、命令行界面(CLI)和注冊表三個不同的組件組成。
5、Webpack
Webpack是現代JavaScript應用程序的模塊打包程序,它將前端開發所辯雀笑需的所有資源(如JavaScript、字體和圖像)集中到一個地方。如果你正在開發復雜的前端,這特別有用。你可以去通過部署具有的WebPack Web應用程序,以獲取有關的WebPack起來和運行。
除了以上工具,還有Sass、React等,根據企業所用工具的不同,你需要掌握的工具也不一樣。