Heim >Web-Frontend >js-Tutorial >Erfahren Sie mehr über NodeJS
Wenn Sie ein Front-End-Entwickler sind, ist das Schreiben von Webprogrammen auf Basis von NodeJS für Sie keine Neuigkeit mehr. Sowohl NodeJS als auch Webprogramme basieren stark auf der JavaScript-Sprache. Zunächst müssen wir eines erkennen: Node ist kein Allheilmittel. Allerdings ist es nicht für jedes Projekt die beste Lösung. Jeder kann einen auf Node basierenden Server erstellen, dies erfordert jedoch ein tiefes Verständnis der Sprache, in der Webprogramme geschrieben sind.
Bevor Node.js erschien, basierten Webanwendungen oft auf dem Client/Server-Modell Fordert Ressourcen an, antwortet der Server auf die Anfrage und gibt die entsprechenden Ressourcen zurück. Der Server antwortet nur, wenn er eine Client-Anfrage erhält, und schließt die Verbindung mit dem Client nach der Antwort.
Dieses Entwurfsmuster muss Effizienzaspekte berücksichtigen, da jede Anfrage Verarbeitungszeit und Ressourcen erfordert. Daher sollte der Server nach jeder Verarbeitung der angeforderten Ressource die Verbindung schließen, um auf andere Anfragen reagieren zu können.
Was passiert mit dem Server, wenn Tausende von Anfragen gleichzeitig an den Server gesendet werden? Wenn Sie diese Frage stellen, möchten Sie nicht, dass eine Anfrage auf die Beantwortung anderer Anfragen warten muss, bevor sie an die Reihe kommt, weil die Verzögerung zu lang ist.
Stellen Sie sich vor, Sie möchten Facebook öffnen, aber da Tausende von Menschen vor Ihnen Anfragen an den Server gestellt haben, müssen Sie 5 Minuten warten, um den Inhalt zu sehen. Gibt es eine Lösung, um Hunderte oder Tausende von Anfragen gleichzeitig zu bearbeiten? Zum Glück haben wir den Tool-Thread.
Threads sind die Art und Weise, wie das System mehrere Aufgaben parallel verarbeiten kann. Jede Anfrage an den Server startet einen neuen Thread und jeder Thread erhält alles, was er zum Ausführen des Codes benötigt.
Klingt das komisch? Schauen wir uns dieses Beispiel an:
Stellen Sie sich ein Restaurant vor, in dem nur ein Koch Essen serviert, während die Nachfrage nach Lebensmitteln steigt, wird es immer schlimmer. Die Leute mussten lange warten, bis alle vorherigen Bestellungen bearbeitet wurden. Und die einzige Möglichkeit, die uns einfällt, ist, mehr Kellner hinzuzufügen, um dieses Problem zu lösen, oder? Dadurch können wir mehr Kunden gleichzeitig betreuen.
Jeder Thread ist ein neuer Kellner, und der Kunde ist der Browser. Ich denke, es fällt Ihnen nicht schwer, das zu verstehen.
Dieses System hat jedoch einen Nebeneffekt, wenn die Anzahl der Anfragen eine bestimmte Anzahl erreicht, belegen zu viele Threads den gesamten Systemspeicher und die gesamten Ressourcen. Um auf unser Beispiel zurückzukommen: Wenn immer mehr Leute für die Essensausgabe eingestellt werden, steigen zwangsläufig die Arbeitskosten und der Platzbedarf in der Küche nimmt zu.
Natürlich wäre es für uns großartig, wenn der Server nach Beantwortung der Anfrage des Clients sofort die Verbindung unterbricht und alle Ressourcen freigibt.
Multithread-Systeme eignen sich gut für die Verarbeitung CPU-intensiver Vorgänge, da diese Vorgänge die Verarbeitung einer großen Menge an Logik erfordern und die Berechnung dieser Logik mehr Zeit in Anspruch nimmt. Wenn jede Anfrage von einem neuen Thread verarbeitet wird, kann der Hauptthread für einige wichtige Berechnungen frei werden, was auch das gesamte System schneller machen kann.
Zuzulassen, dass der Hauptthread nicht mit allen Berechnungsvorgängen beschäftigt ist, ist eine gute Möglichkeit, die Effizienz zu verbessern, aber können wir darüber hinausgehen?
Stellen Sie sich vor, wir haben jetzt einen Multithread-Server, der in einer Ruby on Rails-Umgebung läuft. Wir benötigen es, um die Datei zu lesen und an den Browser zu senden, der die Datei angefordert hat. Das Erste, was Sie wissen müssen, ist, dass Ruby Dateien nicht direkt liest, sondern das Dateisystem anweist, die angegebene Datei zu lesen und ihren Inhalt zurückzugeben. Wie der Name schon sagt, ist ein Dateisystem ein Programm auf Ihrem Computer, das speziell für den Zugriff auf Dateien verwendet wird.
Nachdem Ruby das Dateisystem benachrichtigt hat, wartet es darauf, dass das Lesen der Datei abgeschlossen ist, anstatt sich anderen Aufgaben zu widmen. Wenn die Dateisystemverarbeitungsaufgabe abgeschlossen ist, wird Ruby neu gestartet, um die Dateiinhalte zu sammeln und an den Browser zu senden.
Diese Methode führt offensichtlich zu Blockierungen, und NodeJS wurde geboren, um dieses Problem zu lösen. Wenn wir Node verwenden, um Benachrichtigungen an das Dateisystem zu senden, verarbeitet Node andere Anfragen, während das Dateisystem die Datei liest. Nachdem die Aufgabe zum Lesen der Datei abgeschlossen ist, benachrichtigt das Dateisystem Node, die Ressource zu lesen und an den Browser zurückzugeben. Tatsächlich basiert die interne Implementierung hier auf der Ereignisschleife von Node.
Der Kern von Node ist JavaScript und die Ereignisschleife.
Einfach ausgedrückt ist eine Ereignisschleife ein Programm, das auf Ereignisse wartet und diese dann auslöst, wenn die erforderlichen Ereignisse eintreten. Ein weiterer wichtiger Punkt ist, dass Node wie JavaScript Single-Threaded ist.
Erinnern Sie sich an das Restaurantbeispiel, das wir gegeben haben? Unabhängig von der Anzahl der Kunden gibt es in dem von Node eröffneten Restaurant immer nur einen Koch, der Speisen kocht.
Im Gegensatz zu anderen Sprachen muss NodeJS nicht für jede Anfrage einen neuen Thread öffnen. Es empfängt alle Anfragen und delegiert die meisten Aufgaben dann an andere Systeme. <code><span style="font-size: 14px;">Libuv</span>
Libuv ist eine Bibliothek, die auf dem Betriebssystemkernel basiert, um diese Aufgaben effizient zu erledigen. Wenn diese hinter den Kulissen verborgenen Arbeiter die an sie delegierten Ereignisse verarbeitet haben, lösen sie die an diese Ereignisse gebundenen Rückruffunktionen aus, um NodeJS zu benachrichtigen.
Hier kommen wir mit dem Konzept der Rückrufe in Berührung. Callback ist nicht schwer zu verstehen. Es handelt sich um eine Funktion, die von anderen Funktionen als Parameter übergeben und unter bestimmten Umständen aufgerufen wird.
Was NodeJS-Entwickler am häufigsten tun, ist das Schreiben von Ereignisverarbeitungsfunktionen, und diese Verarbeitungsfunktionen werden aufgerufen, nachdem bestimmte NodeJS-Ereignisse aufgetreten sind.
Obwohl NodeJS Single-Threaded ist, ist es viel schneller als Multithread-Systeme. Dies liegt daran, dass es bei Programmen oft nicht nur um zeitaufwändige mathematische Operationen und logische Verarbeitung geht. Sie schreiben meist nur Dateien, bearbeiten Netzwerkanfragen oder beantragen Berechtigungen von Konsolen und externen Geräten. Dies sind Probleme, mit denen NodeJS gut umgehen kann: Wenn NodeJS diese Dinge erledigt, delegiert es diese Ereignisse schnell an ein spezialisiertes System und kümmert sich dann um das nächste Ereignis.
Wenn Sie weiter tiefer graben, werden Sie vielleicht feststellen, dass NodeJS nicht gut darin ist, CPU-verbrauchende Vorgänge zu bewältigen. Weil CPU-intensive Vorgänge viele Haupt-Thread-Ressourcen beanspruchen. Für ein Single-Thread-System besteht die ideale Situation darin, diese Vorgänge zu vermeiden, um den Haupt-Thread für andere Aufgaben freizugeben.
Ein weiterer wichtiger Punkt ist, dass in JavaScript nur der von Ihnen geschriebene Code nicht gleichzeitig ausgeführt wird. Das heißt, Ihr Code kann jeweils nur an einer Sache arbeiten, während andere Worker, wie etwa das Dateisystem, die anstehende Arbeit parallel erledigen können.
Wer es immer noch nicht versteht, kann sich das folgende Beispiel ansehen:
Vor langer Zeit gab es einen König der tausend Beamte hatte. Der König verfasste eine Liste mit Aufgaben, die die Beamten erledigen mussten, und die Liste war sehr, sehr, sehr lang. Es gibt einen Premierminister, der nach einer Liste Aufgaben an alle anderen Beamten delegiert. Nach jeder erledigten Aufgabe meldete er die Ergebnisse dem König, der ihm dann eine weitere Liste überreichte. Denn während die Beamten arbeiteten, war der König auch damit beschäftigt, andere Listen zu schreiben.
Worum es in diesem Beispiel geht, ist, dass selbst wenn viele Beamte parallel Aufgaben bearbeiten, der König immer nur eine Sache gleichzeitig tun kann. Hier ist Ihr Code der König und die Beamten sind die Systemarbeiter, die sich hinter NodeJS verbergen. Bis auf Ihren Code geschieht also alles parallel.
Okay, lasst uns diese NodeJS-Reise fortsetzen.
Das Schreiben einer Webanwendung mit NodeJS entspricht dem Schreiben eines Ereignisrückrufs. Schauen wir uns das folgende Beispiel an:
Erstellen Sie einen neuen Ordner und geben Sie ihn ein
Führen Sie den Befehl <span style="font-size: 14px;">npm init</span>
<span style="font-size: 14px;">npm init</span>
Erstellen Sie eine neue Datei mit dem Namen server.js, kopieren Sie den folgenden Code und fügen Sie ihn ein:
<span style="font-size: 14px;">//server.js<br>const http = require('http'),<br> server = http.createServer();<br><br>server.on('request',(request,response)=>{<br> response.writeHead(200,{'Content-Type':'text/plain'});<br> response.write('Hello world');<br> response.end();<br>});<br><br>server.listen(3000,()=>{<br> console.log('Node server created at port 3000');<br>});<br></span>
<span style="font-size: 14px;">node server.js</span>
Geben Sie in der Befehlszeile node server.js
<span style="font-size: 14px;">node server.js<br>//Node server started at port 3000<br></span>ein. Sie sehen die folgende Ausgabe:
<span style="font-size: 14px;">localhost:3000</span>
Öffnen Sie Ihren Browser und gehen Sie zu <code><span style="font-size: 14px;">Hello world</span>
localhost:3000. Sie sollten einen
Hallo Welt
Nachricht. 首先,我们引入了http模块。这个模块提供了处理htpp操作的接口,我们调用<span style="font-size: 14px;">createServer()</span>
方法来创建一个服务器。
之后,我们为request事件绑定了一个事件回调,传递给on方法的第二个参数。这个回调函数有2个参数对象,request代表接收到的请求,response代表响应的数据。
不仅仅是处理request事件,我们也可以让Node去做其他事情。
<span style="font-size: 14px;">//server.js<br>const http = require('http'),<br>server = http.createServer((request,response)=>{<br> response.writeHead(200,{'Content-Type':'text/plain'});<br> response.write('Hello world');<br> response.end();<br>});<br>server.listen(3000,()=>{<br> console.log('Node server created at port 3000');<br>});<br></span>
在当面的代码里,我们传给createServer()一个回调函数,Node把它绑定在request事件上。这样我们只需要关心request和response对象了。
我们使用<span style="font-size: 14px;">response.writeHead()</span>
来设置返回报文头部字段,比如状态码和内容类型。而<span style="font-size: 14px;">response.write()</span>
是对web页面进行写入操作。最后使用<span style="font-size: 14px;">response.end()</span>
来结束这个响应。
最后,我们告知服务器去监听3000端口,这样我们可以在本地开发时查看我们web应用的一个demo。listen这个方法要求第二个参数是一个回调函数,服务器一启动,这个回调函数就会被执行。
Node是一个单线程事件驱动的运行环境,也就是说,在Node里,任何事都是对事件的响应。
前文的例子可以改写成下面这样:
<span style="font-size: 14px;">//server.js<br>const http = require('http'),<br> <br>makeServer = function (request,response){<br> response.writeHead(200,{'Content-Type':'text/plain'});<br> response.write('Hello world');<br> response.end();<br>},<br> <br>server = http.createServer(makeServer);<br><br>server.listen(3000,()=>{<br> console.log('Node server created at port 3000');<br></span>
<span style="font-size: 14px;">makeServer</span>
是一个回调函数,由于JavaScript把函数当作一等公民,所以他们可以被传给任何变量或是函数。如果你还不了解JavaScript,你应该花点时间去了解什么是事件驱动程序。
当你开始编写一些重要的JavaScript代码时,你可能会遇到“回调地狱”。你的代码变得难以阅读因为大量的函数交织在一起,错综复杂。这时你想要找到一种更先进、有效的方法来取代回调。看看Promise吧,Eric Elliott 写了一篇文章来讲解什么是Promise,这是一个好的入门教程。
一个服务器会存储大量的文件。当浏览器发送请求时,会告知服务器他们需要的文件,而服务器会将相应的文件返回给客户端。这就叫做路由。
在NodeJS中,我们需要手动定义自己的路由。这并不麻烦,看看下面这个基本的例子:
<span style="font-size: 14px;">//server.js<br>const http = require('http'),<br> url = require('url'),<br> <br>makeServer = function (request,response){<br> let path = url.parse(request.url).pathname;<br> console.log(path);<br> if(path === '/'){<br> response.writeHead(200,{'Content-Type':'text/plain'});<br> response.write('Hello world');<br> }<br> else if(path === '/about'){<br> response.writeHead(200,{'Content-Type':'text/plain'});<br> response.write('About page');<br> }<br> else if(path === '/blog'){<br> response.writeHead(200,{'Content-Type':'text/plain'});<br> response.write('Blog page');<br> }<br> else{<br> response.writeHead(404,{'Content-Type':'text/plain'});<br> response.write('Error page');<br> }<br> response.end();<br> },<br>server = http.createServer(makeServer);<br>server.listen(3000,()=>{<br> console.log('Node server created at port 3000');<br>});<br></span>
粘贴这段代码,输入<span style="font-size: 14px;">node server.js</span>
命令来运行。在浏览器中打开<span style="font-size: 14px;">localhost:3000</span>
和<span style="font-size: 14px;">localhost:3000/abou</span>
,然后在试试打开<span style="font-size: 14px;">localhost:3000/somethingelse</span>
,是不是跳转到了我们的错误页面?
虽然这样满足了我们启动服务器的基本要求,但是要为服务器上每一个网页都写一遍代码实在是太疯狂了。事实上没有人会这么做,这个例子只是让你了解路由是怎么工作的。
如果你有注意到,我们引入了url这个模块,它能让我们处理url更加方便。
为parse()方法传入一个url字符串参数,这个方法会将url拆分成<span style="font-size: 14px;">protocol</span>
、<span style="font-size: 14px;">host</span>
、<span style="font-size: 14px;">path</span>
和<span style="font-size: 14px;">querystring</span>
等部分。如果你不太了解这些单词,可以看看下面这张图:
所以当我们执行<span style="font-size: 14px;">url.parse(request.url).pathname</span>
语句时,我们得到一个url路径名,或者是url本身。这些都是我们用来进行路由请求的必要条件。不过这件事还有个更简单的方法。
如果你之前做过功课,你一定听说过Express。这是一个用来构建web应用以及API的NodeJS框架,它也可以用来编写NodeJS应用。接着往下看,你会明白为什么我说它让一切变得更简单。
在你的终端或是命令行中,进入电脑的根目录,输入<span style="font-size: 14px;">npm install express --save</span>
来安装Express模块包。要在项目中使用Express,我们需要引入它。
<span style="font-size: 14px;">const express = require('express');<br></span>
欢呼吧,生活将变得更美好。
现在,让我们用express进行基本的路由。
<span style="font-size: 14px;">//server.js<br>const express = require('express'),<br> server = express();<br><br>server.set('port', process.env.PORT || 3000);<br><br>//Basic routes<br>server.get('/', (request,response)=>{<br> response.send('Home page');<br>});<br><br>server.get('/about',(request,response)=>{<br> response.send('About page');<br>});<br><br>//Express error handling middleware<br>server.use((request,response)=>{<br> response.type('text/plain');<br> response.status(505);<br> response.send('Error page');<br>});<br><br>//Binding to a port<br>server.listen(3000, ()=>{<br> console.log('Express server started at port 3000');<br>});<br></span>
译者注:这里不是很理解为什么代码中错误状态码是505。
现在的代码是不是看上去更加清晰了?我相信你很容易就能理解它。
首先,当我们引入express模块后,得到的是一个函数。调用这个函数后就可以开始启动我们的服务器了。
接下来,我们用<span style="font-size: 14px;">server.set()</span>
来设置监听端口。而<span style="font-size: 14px;">process.env.PORT</span>
是程序运行时的环境所设置的。如果没有这个设置,我们默认它的值是3000.
然后,观察上面的代码,你会发现Express里的路由都遵循一个格式:
<span style="font-size: 14px;">server.VERB('route',callback);<br></span>
这里的VERB可以是GET、POST等动作,而pathname是跟在域名后的字符串。同时,callback是我们希望接收到一个请求后触发的函数。
最后我们再调用<span style="font-size: 14px;">server.listen()</span>
,还记得它的作用吧?
以上就是Node程序里的路由,下面我们来挖掘一下Node如何调用数据库。
很多人喜欢用JavaScript来做所有事。刚好有一些数据库满足这个需求,比如MongoDB、CouchDB等待。这些数据库都是NoSQL数据库。
一个NoSQL数据库以键值对的形式作为数据结构,它以文档为基础,数据都不以表格形式保存。
我们来可以看看MongoDB这个NoSQL数据库。如果你使用过MySQL、SQLserver等关系型数据库,你应该熟悉数据库、表格、行和列等概念。 MongoDB与他们相比并没有特别大的区别,不过还是来比较一下吧。
译者注:这儿应该有个表格显示MongoDB与MySQL的区别,但是原文里没有显示。
为了让数据更加有组织性,在向MongoDB插入数据之前,我们可以使用Mongoose来检查数据类型和为文档添加验证规则。它看上去就像Mongo与Node之间的中介人。
由于本文篇幅较长,为了保证每一节都尽可能的简短,请你先阅读官方的MongoDB安装教程。
此外,Chris Sevilleja写了一篇Easily Develop Node.js and MongoDB Apps with Mongoose,我认为这是一篇适合入门的基础教程。
API是应用程序向别的程序发送数据的通道。你有没有登陆过某些需要你使用facebook账号登录的网页?facebook将某些函数公开给这些网站使用,这些就是API。
一个RESTful API应该不以服务器/客户端的状态改变而改变。通过使用一个REST接口,不同的客户端,即使它们的状态各不相同,但是在访问相同的REST终端时,应该做出同一种动作,并且接收到相同的数据。
API终端是API里返回数据的一个函数。
编写一个RESTful API涉及到使用JSON或是XML格式传输数据。让我们在NodeJS里试试吧。我们接下来会写一个API,它会在客户端通过AJAX发起请求后返回一个假的JSON数据。这不是一个理想的API,但是能帮助我们理解在Node环境中它是怎么工作的。
创建一个叫node-api的文件夹;
通过命令行进入这个文件夹,输入<span style="font-size: 14px;">npm init</span>
。这会创建一个收集依赖的文件;
输入<span style="font-size: 14px;">npm install --save express</span>
来安装express;
在根目录新建3个文件:<span style="font-size: 14px;">server.js</span>
,<span style="font-size: 14px;">index.html</span>
和<span style="font-size: 14px;">users.js</span>
;
复制下面的代码到相应的文件:
<span style="font-size: 14px;">//users.js<br>module.exports.users = [<br> {<br> name: 'Mark',<br> age : 19,<br> occupation: 'Lawyer',<br> married : true,<br> children : ['John','Edson','ruby']<br> },<br> <br> {<br> name: 'Richard',<br> age : 27,<br> occupation: 'Pilot',<br> married : false,<br> children : ['Abel']<br> },<br> <br> {<br> name: 'Levine',<br> age : 34,<br> occupation: 'Singer',<br> married : false,<br> children : ['John','Promise']<br> },<br> <br> {<br> name: 'Endurance',<br> age : 45,<br> occupation: 'Business man',<br> married : true,<br> children : ['Mary']<br> },<br>]<br></span>
这是我们传给别的应用的数据,我们导出这份数据让所有程序都可以使用。也就是说,我们将users这个数组保存在<span style="font-size: 14px;">modules.exports</span>
对象中。
<span style="font-size: 14px;">//server.js<br>const express = require('express'),<br> server = express(),<br> users = require('./users');<br><br>//setting the port.<br>server.set('port', process.env.PORT || 3000);<br><br>//Adding routes<br>server.get('/',(request,response)=>{<br> response.sendFile(__dirname + '/index.html');<br>});<br><br>server.get('/users',(request,response)=>{<br> response.json(users);<br>});<br><br>//Binding to localhost://3000<br>server.listen(3000,()=>{<br> console.log('Express server started at port 3000');<br>});<br></span>
我们执行<span style="font-size: 14px;">require('express')</span>
语句然后使用<span style="font-size: 14px;">express()</span>
创建了一个服务变量。如果你仔细看,你还会发现我们引入了别的东西,那就是<span style="font-size: 14px;">users.js</span>
。还记得我们把数据放在哪了吗?要想程序工作,它是必不可少的。
express有许多方法帮助我们给浏览器传输特定类型的内容。<span style="font-size: 14px;">response.sendFile()</span>
会查找文件并且发送给服务器。我们使用<span style="font-size: 14px;">__dirname</span>
来获取服务器运行的根目录路径,然后我们把字符串<span style="font-size: 14px;">index.js</span>
加在路径后面保证我们能够定位到正确的文件。
<span style="font-size: 14px;">response.json()</span>
向网页发送JSON格式内容。我们把要分享的users数组传给它当参数。剩下的代码我想你在之前的文章中已经很熟悉了。
<span style="font-size: 14px;">//index.html<br><br><!DOCTYPE html><br><html><br><head><br> <meta charset="utf-8"><br> <title>Home page</title><br></head><br><body><br> <button>Get data</button><br><script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script><br> <br> <script type="text/javascript"><br> <br> const btn = document.querySelector('button');<br> btn.addEventListener('click',getData);<br> function getData(e){<br> $.ajax({<br> url : '/users',<br> method : 'GET',<br> success : function(data){<br> console.log(data);<br> },<br> <br> error: function(err){<br> console.log('Failed');<br> }<br> });<br> } <br> </script><br></body><br></html><br></span>
在文件夹根目录中执行<span style="font-size: 14px;">node server.js</span>
,现在打开你的浏览器访问<span style="font-size: 14px;">localhost:3000</span>
,按下按钮并且打开你的浏览器控制台。
在<span style="font-size: 14px;">btn.addEventListent('click',getData);</span>
这行代码里,getData通过AJAX发出一个GET请求,它使用了<span style="font-size: 14px;">$.ajax({properties})</span>
函数来设置<span style="font-size: 14px;">url</span>
,<span style="font-size: 14px;">success</span>
和<span style="font-size: 14px;">error</span>
等参数。
在实际生产环境中,你要做的不仅仅是读取JSON文件。你可能还想对数据进行增删改查等操作。express框架会将这些操作与特定的http动词绑定,比如POST、GET、PUT和DELETE等关键字。
要想深入了解使用express如何编写API,你可以去阅读Chris Sevilleja写的Build a RESTful API with Express 4。
计算机网络是计算机之间分享接收数据的连接。要在NodeJS中进行连网操作,我们需要引入<span style="font-size: 14px;">net</span>
模块。
<span style="font-size: 14px;">const net = require('net');<br></span>
在TCP中必须有两个终端,一个终端与指定端口绑定,而另一个则需要访问这个指定端口。
如果你还有疑惑,可以看看这个例子:
以你的手机为例,一旦你买了一张sim卡,你就和sim的电话号码绑定。当你的朋友想要打电话给你时,他们必须拨打这个号码。这样你就相当于一个TCP终端,而你的朋友是另一个终端。
现在你明白了吧?
为了更好地吸收这部分知识,我们来写一个程序,它能够监听文件并且当文件被更改后会通知连接到它的客户端。
创建一个文件夹,命名为<span style="font-size: 14px;">node-network</span>
;
创建3个文件:<span style="font-size: 14px;">filewatcher.js</span>
、<span style="font-size: 14px;">subject.txt</span>
和<span style="font-size: 14px;">client.js</span>
。把下面的代码复制进<span style="font-size: 14px;">filewatcher.js</span>
。
<span style="font-size: 14px;">//filewatcher.js<br><br>const net = require('net'),<br> fs = require('fs'),<br> filename = process.argv[2],<br> <br>server = net.createServer((connection)=>{<br> console.log('Subscriber connected');<br> connection.write(`watching ${filename} for changes`);<br> <br>let watcher = fs.watch(filename,(err,data)=>{<br> connection.write(`${filename} has changed`);<br> });<br> <br>connection.on('close',()=>{<br> console.log('Subscriber disconnected');<br> watcher.close();<br> });<br> <br>});<br>server.listen(3000,()=>console.log('listening for subscribers'));<br></span>
接下来我们提供一个被监听的文件,在<span style="font-size: 14px;">subject.txt</span>
写下下面一段话:
<span style="font-size: 14px;">Hello world, I'm gonna change<br></span>
然后,新建一个客户端。下面的代码复制到<span style="font-size: 14px;">client.js</span>
。
<span style="font-size: 14px;">const net = require('net');<br>let client = net.connect({port:3000});<br>client.on('data',(data)=>{<br> console.log(data.toString());<br>});<br></span>
最后,我们还需要两个终端。第一个终端里我们运行<span style="font-size: 14px;">filename.js</span>
,后面跟着我们要监听的文件名。
<span style="font-size: 14px;">//subject.txt会保存在filename变量中<br>node filewatcher.js subject.txt<br>//监听订阅者<br></span>
在另一个终端,也就是客户端,我们运行<span style="font-size: 14px;">client.js</span>
。
<span style="font-size: 14px;">node client.js<br></span>
现在,修改<span style="font-size: 14px;">subject.txt</span>
,然后看看客户端的命令行,注意到多出了一条额外信息:
<span style="font-size: 14px;">//subject.txt has changed.<br></span>
网络的一个主要的特征就是许多客户端都可以同时接入这个网络。打开另一个命令行窗口,输入<span style="font-size: 14px;">node client.js</span>
来启动另一个客户端,然后再修改<span style="font-size: 14px;">subject.txt</span>
文件。看看输出了什么?
如果你没有理解,不要担心,让我们重新过一遍。
我们的<span style="font-size: 14px;">filewatcher.js</span>
做了三件事:
<span style="font-size: 14px;">net.createServer()</span>
创建一个服务器并向许多客户端发送信息。
通知服务器有客户端连接,并且告知客户端有一个文件被监听。
最后,使用wactherbianl监听文件,并且当客户端端口连接时关闭它。
再来看一次<span style="font-size: 14px;">filewatcher.js</span>
。
<span style="font-size: 14px;">//filewatcher.js<br><br>const net = require('net'),<br> fs = require('fs'),<br> filename = process.argv[2],<br> <br>server = net.createServer((connection)=>{<br> console.log('Subscriber connected');<br> connection.write(`watching ${filename} for changes`);<br> <br>let watcher = fs.watch(filename,(err,data)=>{<br> connection.write(`${filename} has changed`);<br> });<br> <br>connection.on('close',()=>{<br> console.log('Subscriber disconnected');<br> watcher.close();<br> });<br> <br>});<br>server.listen(3000,()=>console.log('listening for subscribers'));<br></span>
我们引入两个模块:fs和net来读写文件和执行网络连接。你有注意到<span style="font-size: 14px;">process.argv[2]</span>
吗?process是一个全局变量,提供NodeJS代码运行的重要信息。<span style="font-size: 14px;">argv[]</span>
是一个参数数组,当我们获取<span style="font-size: 14px;">argv[2]</span>
时,希望得到运行代码的第三个参数。还记得在命令行中,我们曾输入文件名作为第三个参数吗?
<span style="font-size: 14px;">node filewatcher.js subject.txt<br></span>
此外,我们还看到一些非常熟悉的代码,比如<span style="font-size: 14px;">net.createServer()</span>
,这个函数会接收一个回调函数,它在客户端连接到端口时触发。这个回调函数只接收一个用来与客户端交互的对象参数。
<span style="font-size: 14px;">connection.write()</span>
方法向任何连接到3000端口的客户端发送数据。这样,我们的<span style="font-size: 14px;">connetion</span>
对象开始工作,通知客户端有一个文件正在被监听。
wactcher包含一个方法,它会在文件被修改后发送信息给客户端。而且在客户端断开连接后,触发了close事件,然后事件处理函数会向服务器发送信息让它关闭watcher停止监听。
<span style="font-size: 14px;">//client.js<br>const net = require('net'),<br> client = net.connect({port:3000});<br>client.on('data',(data)=>{<br> console.log(data.toString());<br>});<br></span>
<span style="font-size: 14px;">client.js</span>
很简单,我们引入net模块并且调用connect方法去访问3000端口,然后监听每一个data事件并打印出数据。
当我们的<span style="font-size: 14px;">filewatcher.js</span>
每执行一次<span style="font-size: 14px;">connection.write()</span>
,我们的客户端就会触发一次data事件。
以上只是网络如何工作的一点皮毛。主要就是一个端点广播信息时会触发所有连接到这个端点的客户端上的data事件。
如果你想要了解更多Node的网络知识,可以看看官方NodeJS的文档:net模块。你也许还需要阅读Building a Tcp service using Node。
相关推荐:
Das obige ist der detaillierte Inhalt vonErfahren Sie mehr über NodeJS. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!