> 웹 프론트엔드 > JS 튜토리얼 > NodeJS에 대해 자세히 알아보기

NodeJS에 대해 자세히 알아보기

小云云
풀어 주다: 2018-02-10 16:15:01
원래의
2477명이 탐색했습니다.

프런트 엔드 개발자라면 NodeJS를 기반으로 웹 프로그램을 작성하는 것이 더 이상 새로운 것이 아닙니다. NodeJS와 웹 프로그램 모두 JavaScript 언어에 크게 의존합니다. 먼저 우리는 한 가지 사실을 깨달아야 합니다. 노드는 만병통치약이 아닙니다. 즉, 모든 프로젝트에 가장 적합한 솔루션은 아닙니다. 누구나 Node 기반의 서버를 만들 수 있지만 이를 위해서는 웹 프로그램이 작성되는 언어에 대한 깊은 이해가 필요합니다.

Node.js 이전

Node.js가 등장하기 전에는 웹 애플리케이션이 클라이언트/서버 모델을 기반으로 하는 경우가 많았습니다. 클라이언트가 서버에 리소스를 요청하면 서버는 요청에 응답하고 해당 리소스를 반환합니다. 자원. 서버는 클라이언트 요청을 받을 때만 응답하고, 응답 후에는 클라이언트와의 연결을 닫습니다.

각 요청에는 처리 시간과 리소스가 필요하므로 이 디자인 패턴은 효율성 문제를 고려해야 합니다. 따라서 서버는 다른 요청에 응답하기 위해 요청된 리소스를 처리할 때마다 연결을 닫아야 합니다.

수천개의 요청이 동시에 서버로 전송된다면 서버는 어떤 모습일까요? 이 질문을 할 때 한 요청이 차례를 마치기 전에 다른 요청이 응답될 때까지 기다려야 하는 상황을 보고 싶지 않을 것입니다. 왜냐하면 지연 시간이 너무 길기 때문입니다.

FaceBook을 열고 싶은데 수천 명의 사람들이 먼저 서버에 요청했기 때문에 콘텐츠를 보려면 5분을 기다려야 한다고 상상해 보세요. 수백 또는 수천 개의 요청을 동시에 처리할 수 있는 솔루션이 있습니까? 다행히 도구 스레드가 있습니다.

스레드는 시스템이 여러 작업을 병렬로 처리할 수 있는 방법입니다. 서버에 대한 각 요청은 새 스레드를 시작하고 각 스레드는 코드를 실행하는 데 필요한 모든 것을 가져옵니다.

이상하게 들리나요? 다음 예를 살펴보겠습니다.

음식점에 음식을 제공하는 요리사가 단 한 명 있다고 상상해 보세요. 음식에 대한 수요가 증가하면 상황은 점점 더 나빠질 것입니다. 사람들은 이전 주문이 모두 처리되기까지 오랜 시간을 기다려야 했습니다. 그리고 우리가 생각할 수 있는 유일한 방법은 이 문제를 해결하기 위해 웨이터를 더 추가하는 것입니다. 그렇죠? 이를 통해 동시에 더 많은 고객을 처리할 수 있습니다.

모든 스레드는 새로운 웨이터이고 고객은 브라우저입니다. 나는 당신이 이것을 이해하는 것이 어렵지 않다고 생각합니다.

하지만 이 시스템에는 요청 수가 특정 수에 도달하면 너무 많은 스레드가 전체 시스템 메모리와 리소스를 차지하게 되는 부작용이 있습니다. 우리의 예로 돌아가서, 음식을 서빙하기 위해 점점 더 많은 사람을 고용하면 필연적으로 인건비가 증가하고 더 많은 주방 공간을 차지하게 됩니다.

물론, 서버가 클라이언트의 요청에 응답한 후 즉시 연결을 끊고 모든 리소스를 해제한다면 우리에게는 좋을 것입니다.

멀티 스레드 시스템은 CPU 집약적인 작업을 처리하는 데 적합합니다. 이러한 작업에는 처리하는 데 많은 논리가 필요하고 이러한 논리를 계산하는 데 더 많은 시간이 걸리기 때문입니다. 각 요청이 새 스레드에 의해 처리되면 메인 스레드를 비워 몇 가지 중요한 계산을 처리할 수 있으며, 이로 인해 전체 시스템이 더 빨라질 수도 있습니다.

메인 스레드가 모든 계산 작업으로 바쁠 필요가 없도록 효율성을 높이는 좋은 방법이지만, 이 이상 더 나아갈 수 있을까요?

NodeJS 출시

이제 Ruby on Rails 환경에서 실행되는 다중 스레드 서버가 있다고 상상해 보세요. 파일을 읽고 파일을 요청한 브라우저로 보내는 데 필요합니다. 가장 먼저 알아야 할 점은 Ruby는 파일을 직접 읽지 않고 대신 파일 시스템에 지정된 파일을 읽고 그 내용을 반환하도록 지시한다는 것입니다. 이름에서 알 수 있듯이 파일 시스템은 파일에 액세스하는 데 특별히 사용되는 컴퓨터의 프로그램입니다.

파일 시스템에 알림을 보낸 후 Ruby는 다른 작업을 처리하기 위해 돌아서는 대신 파일 읽기가 완료될 때까지 기다립니다. 파일 시스템 처리 작업이 완료되면 Ruby는 파일 내용을 수집하고 브라우저로 보내기 위해 다시 시작합니다.

이 방법은 분명히 차단을 유발하므로 NodeJS는 이러한 문제점을 해결하기 위해 탄생했습니다. Node를 사용하여 파일 시스템에 알림을 보내는 경우 Node는 파일 시스템이 파일을 읽는 동안 다른 요청을 처리합니다. 파일 읽기 작업이 완료된 후 파일 시스템은 노드에 리소스를 읽고 브라우저에 반환하도록 알립니다. 실제로 여기서 내부 구현은 Node의 이벤트 루프에 의존합니다.

Node의 핵심은 JavaScript와 이벤트 루프입니다.

NodeJS에 대해 자세히 알아보기

간단히 말하면, 이벤트 루프는 이벤트를 기다렸다가 필요한 이벤트가 발생할 때 이를 트리거하는 프로그램입니다. 또 다른 중요한 점은 Node가 JavaScript와 마찬가지로 단일 스레드라는 것입니다.

우리가 제시한 레스토랑 예시를 기억하시나요? 노드가 오픈한 레스토랑에는 손님 수에 관계없이 항상 한 명의 셰프만이 음식을 조리하고 있다.

다른 언어와 달리 NodeJS는 각 요청에 대해 새 스레드를 열 필요가 없으며 모든 요청을 받은 다음 대부분의 작업을 다른 시스템에 위임합니다. <code><span style="font-size: 14px;">Libuv</span>就是一个依赖于OS内核去高效处理这些任务的库。当这些隐藏于幕后的工作者处理完委托给它们的事件后,它们会触发绑定在这些事件上的回调函数去通知NodeJS。

这儿我们接触到了回调这个概念。回调理解起来并不困难,它是被其他函数当作参数传递的函数,并且在某种特定情况下会被调用。

NodeJS开发者们做的最多的就是编写事件处理函数,而这些处理函数会在特定的NodeJS事件发生后被调用。

NodeJS虽然是单线程,但它比多线程系统要快得多。这是因为程序往往并不是只有耗时巨长的数学运算和逻辑处理,大部分时间里它们只是写入文件、处理网络请求或是向控制台和外部设备申请权限。这些都是NodeJS擅长处理的问题:当NodeJS在处理这些事情时,它会迅速将这些事件委托给专门的系统,转而去处理下一个事件。

如果你继续深入下去,你也许会意识到NodeJS并不擅长处理消耗CPU的操作。因为CPU密集型操作会占用大量的主线程资源。对于单线程系统来说,最理想的情况就是避免这些操作来释放主线程去处理别的事情。

还有一个关键点是在JavaScript中,只有你写的代码不是并发执行的。也就是说,你的代码每次只能处理一件事,而其他工作者,比如文件系统可以并行处理它们手头的工作。

如果你还不能理解的话,可以看看下面的例子:

很久以前有一个国王,他有一千个官员。国王写了一个任务清单让官员去做,清单非常非常非常长。有一个宰相,根据清单将任务委托给其他所有官员。每完成一项任务他就将结果报告给国王,之后国王又会给他另一份清单。因为在官员工作的时候,国王也在忙于写其他清单。

这个例子要讲的是即使有很多官员在并行处理任务,国王每次也只能做一件事。这里,国王就是你的代码,而官员就是藏于NodeJS幕后的系统工作者。所以说,除了你的代码,每件事都是并行发生的。

好了,让我们继续这段NodeJS之旅吧。

用NodeJS写一个web应用

用NodeJS写一个web应用相当于编写事件回调。让我们来看看下面的例子:

  1. 新建并进入一个文件夹

  2. 执行<span style="font-size: 14px;">npm init</span>命令,一直回车直到你在文件夹根目录下创建了一个package.json文件。

  3. 新建一个名为server.js的文件,复制并粘贴下面的代码:

    <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>
    로그인 후 복사
  4. 在命令行中,输入<span style="font-size: 14px;">node server.js</span>,你会看到下面的输出:

    <span style="font-size: 14px;">node server.js<br>//Node server started at port 3000<br></span>
    로그인 후 복사

    打开浏览器并且进入<span style="font-size: 14px;">localhost:3000</span>,你应该能够看到一个<span style="font-size: 14px;">Hello world</span>Libuv는 이러한 작업을 효율적으로 처리하기 위해 OS 커널을 사용하는 라이브러리입니다. 배후에 숨겨진 작업자가 자신에게 위임된 이벤트를 처리하면 이러한 이벤트에 바인딩된 콜백 함수를 트리거하여 NodeJS에 알립니다.

    🎜🎜🎜여기서 콜백의 개념을 접하게 됩니다. 콜백은 이해하기 어렵지 않습니다. 다른 함수에 의해 매개변수로 전달되며 특정 상황에서 호출되는 함수입니다. 🎜🎜🎜🎜NodeJS 개발자가 가장 많이 하는 일은 이벤트 처리 함수를 작성하는 것이며, 이러한 처리 함수는 특정 NodeJS 이벤트가 발생한 후에 호출됩니다. 🎜🎜🎜🎜NodeJS는 단일 스레드이지만 다중 스레드 시스템보다 훨씬 빠릅니다. 이는 프로그램이 단지 시간이 많이 걸리는 수학적 연산 및 논리적 처리에만 국한되지 않는 경우가 많기 때문입니다. 대부분의 경우 파일을 작성하거나 네트워크 요청을 처리하거나 콘솔 및 외부 장치에 권한을 신청하는 것뿐입니다. 이는 NodeJS가 잘 처리하는 문제입니다. NodeJS가 이러한 문제를 처리할 때 이러한 이벤트를 특수 시스템에 신속하게 위임하고 다음 이벤트를 처리하기 위해 이동합니다. 🎜🎜🎜🎜계속해서 더 깊이 파고들면 NodeJS가 CPU를 많이 사용하는 작업을 잘 처리하지 못한다는 것을 깨닫게 될 것입니다. CPU 집약적인 작업은 많은 메인 스레드 리소스를 차지하기 때문입니다. 단일 스레드 시스템의 경우 이상적인 상황은 다른 작업을 처리하기 위해 메인 스레드를 확보하기 위해 이러한 작업을 피하는 것입니다. 🎜🎜🎜🎜또 다른 핵심 포인트는 JavaScript에서는 작성한 코드만 동시에 실행되지 않는다는 것입니다. 즉, 코드는 한 번에 한 가지 작업만 수행할 수 있는 반면, 파일 시스템과 같은 다른 작업자는 현재 작업을 병렬로 처리할 수 있습니다. 🎜🎜🎜🎜아직 이해가 되지 않는다면 다음 예를 살펴보세요. 🎜🎜🎜🎜옛날에 천 명의 관리를 거느린 왕이 있었습니다. 왕은 관리들이 해야 할 일의 목록을 작성했는데, 그 목록은 아주 아주 아주 길었습니다. 목록에 따라 다른 모든 공무원에게 업무를 위임하는 총리가 있습니다. 그는 임무를 완수할 때마다 그 결과를 왕에게 보고했고, 왕은 그에게 또 다른 목록을 주곤 했습니다. 관리들이 일하는 동안 왕은 다른 목록을 작성하느라 바빴기 때문입니다. 🎜🎜🎜🎜이 예는 여러 관료가 동시에 업무를 처리하더라도 왕은 한 번에 한 가지 일만 할 수 있다는 것입니다. 여기서 왕은 당신의 코드이고 공무원은 NodeJS 뒤에 숨겨진 시스템 작업자입니다. 따라서 코드를 제외한 모든 것이 병렬로 발생합니다. 🎜🎜🎜🎜좋아요, NodeJS 여정을 계속하겠습니다. 🎜🎜

    🎜NodeJS로 웹 애플리케이션 작성🎜

    🎜🎜NodeJS로 웹 애플리케이션 작성은 이벤트 콜백을 작성하는 것과 같습니다. 다음 예를 살펴보겠습니다. 🎜🎜
    1. 🎜🎜폴더 생성 및 입력🎜🎜
    2. 🎜🎜Execute🎜 🎜 npm init🎜🎜 명령을 실행하려면 폴더의 루트 디렉터리에 package.json 파일이 생성될 때까지 Enter 키를 누르세요. 🎜🎜
    3. 🎜🎜server.js라는 새 파일을 만들고 다음 코드를 복사하여 붙여넣습니다. 🎜🎜
      <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>
      로그인 후 복사
      로그인 후 복사
    4. 🎜🎜명령줄에 🎜 🎜를 입력합니다. node server.js🎜🎜, 다음 출력이 표시됩니다. 🎜🎜
      <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>
      로그인 후 복사
      로그인 후 복사
      🎜🎜브라우저를 열고 🎜🎜localhost:3000🎜🎜을 입력하면 A를 볼 수 있습니다. 🎜🎜Hello world🎜🎜 메시지입니다. 🎜🎜

    首先,我们引入了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路由

    一个服务器会存储大量的文件。当浏览器发送请求时,会告知服务器他们需要的文件,而服务器会将相应的文件返回给客户端。这就叫做路由。

    在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>等部分。如果你不太了解这些单词,可以看看下面这张图:

    NodeJS에 대해 자세히 알아보기

    所以当我们执行<span style="font-size: 14px;">url.parse(request.url).pathname</span>语句时,我们得到一个url路径名,或者是url本身。这些都是我们用来进行路由请求的必要条件。不过这件事还有个更简单的方法。

    使用Express进行路由

    如果你之前做过功课,你一定听说过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如何调用数据库。

    NodeJS里的数据库

    很多人喜欢用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,我认为这是一篇适合入门的基础教程。

    使用Node和Express编写RESTful API

    API是应用程序向别的程序发送数据的通道。你有没有登陆过某些需要你使用facebook账号登录的网页?facebook将某些函数公开给这些网站使用,这些就是API。

    一个RESTful API应该不以服务器/客户端的状态改变而改变。通过使用一个REST接口,不同的客户端,即使它们的状态各不相同,但是在访问相同的REST终端时,应该做出同一种动作,并且接收到相同的数据。

    API终端是API里返回数据的一个函数。

    编写一个RESTful API涉及到使用JSON或是XML格式传输数据。让我们在NodeJS里试试吧。我们接下来会写一个API,它会在客户端通过AJAX发起请求后返回一个假的JSON数据。这不是一个理想的API,但是能帮助我们理解在Node环境中它是怎么工作的。

    1. 创建一个叫node-api的文件夹;

    2. 通过命令行进入这个文件夹,输入<span style="font-size: 14px;">npm init</span>。这会创建一个收集依赖的文件;

    3. 输入<span style="font-size: 14px;">npm install --save express</span>来安装express;

    4. 在根目录新建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>

    5. 复制下面的代码到相应的文件:

    <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>,按下按钮并且打开你的浏览器控制台。

    NodeJS에 대해 자세히 알아보기

    <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。

    使用socket进行网络连接

    计算机网络是计算机之间分享接收数据的连接。要在NodeJS中进行连网操作,我们需要引入<span style="font-size: 14px;">net</span>模块。

    <span style="font-size: 14px;">const net = require('net');<br></span>
    로그인 후 복사

    在TCP中必须有两个终端,一个终端与指定端口绑定,而另一个则需要访问这个指定端口。

    如果你还有疑惑,可以看看这个例子:

    以你的手机为例,一旦你买了一张sim卡,你就和sim的电话号码绑定。当你的朋友想要打电话给你时,他们必须拨打这个号码。这样你就相当于一个TCP终端,而你的朋友是另一个终端。

    现在你明白了吧?

    为了更好地吸收这部分知识,我们来写一个程序,它能够监听文件并且当文件被更改后会通知连接到它的客户端。

    1. 创建一个文件夹,命名为<span style="font-size: 14px;">node-network</span>

    2. 创建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>
      로그인 후 복사
      로그인 후 복사
    3. 接下来我们提供一个被监听的文件,在<span style="font-size: 14px;">subject.txt</span>写下下面一段话:

      <span style="font-size: 14px;">Hello world, I'm gonna change<br></span>
      로그인 후 복사
    4. 然后,新建一个客户端。下面的代码复制到<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>
      로그인 후 복사
    5. 最后,我们还需要两个终端。第一个终端里我们运行<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>做了三件事:

    1. <span style="font-size: 14px;">net.createServer()</span>创建一个服务器并向许多客户端发送信息。

    2. 通知服务器有客户端连接,并且告知客户端有一个文件被监听。

    3. 最后,使用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。

    相关推荐:

    Nodejs调用WebService的详解

    NodeJs数据库异常处理解析

    nodejs基础知识

위 내용은 NodeJS에 대해 자세히 알아보기의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿