游过对岸 發表於 2021-6-17 17:58:00

Node.js学习

<p>官方站点:Node.js</p>
<p>Node.js从零开始</p>
<h2>介绍</h2>
<p>Node.js&nbsp;是一个&nbsp;Javascript&nbsp;运行环境(runtime)。</p>
<p>实际上它是对&nbsp;Google V8&nbsp;引擎进行了封装,V8&nbsp;引擎执行JavaScript&nbsp;的速度非常快,性能非常好;而&nbsp;Node.js&nbsp;对一些特殊用例进行了优化,提供了替代的&nbsp;API,使得&nbsp;V8&nbsp;在非浏览器环境下运行得更好,用于方便地搭建响应速度快、易于扩展的网络应用。</p>
<p>Node.js&nbsp;使用事件驱动,非阻塞&nbsp;I/O&nbsp;模型而得以轻量和高效,非常适合在分布式设备上运行数据密集型的实时应用。</p>
<p>node.js是前端or后端?</p>
<ul>
<li>node.js本身不属于前端,但是属于前端的技术栈。</li>
<li>node.js是前端工具链的重要成员,它参与前端开发,属于前端技术栈里的前端工具。类似于GWT,或者编辑器,它本身并不是属于前端。</li>
<li>node.js是js的运行环境,即可以服务于前端,也可以服务于后端。</li>
</ul>
<h2>特点</h2>
<p>对性能的苛求是&nbsp;Node&nbsp;的一个关键因素,JavaScript&nbsp;是一个事件驱动语言,Node&nbsp;利用了这个优点,编写出可扩展性高的服务器。</p>
<p>作为一个新兴的后台语言,Node.js&nbsp;有很多吸引人的地方:</p>
<ul>
<li>RESTful API</li>
<li>单线程:Node.js&nbsp;可以在不新增额外线程的情况下,依然可以对任务进行并行处理 ——&nbsp;<span style="color: rgba(255, 0, 0, 1)">Node.js&nbsp;是单线程的</span><span style="color: rgba(255, 0, 0, 1)">;它</span><span style="color: rgba(255, 0, 0, 1)">通过事件轮询(event loop)来实现并行操作</span>,对此,我们应该要充分利用这一点 —— 尽可能的避免阻塞操作,取而代之,多使用非阻塞操作。</li>
<li>非阻塞&nbsp;I/O</li>
<li>V8&nbsp;虚拟机</li>
<li>事件驱动</li>
</ul>
<h2>模块</h2>
<p>Node.js&nbsp;使用&nbsp;Module(模块)去划分不同的功能,以简化应用的开发。</p>
<p>模块有点像&nbsp;C++&nbsp;语言中的类库,每一个&nbsp;Node.js&nbsp;的类库都包含了十分丰富的各类函数,比如&nbsp;http&nbsp;模块就包含了和&nbsp;http&nbsp;功能相关的很多函数,可以帮助开发者很容易地对比如&nbsp;http、tcp/udp&nbsp;等进行操作,还可以很容易的创建&nbsp;http&nbsp;和&nbsp;tcp/udp&nbsp;的服务器。</p>
<p>要在程序中使用模块是十分方便的,一般是如下步骤:</p>
<p>首先安装模块,比如通过&nbsp;NPM&nbsp;或者&nbsp;yarn&nbsp;这类包管理工具来找到并安装对应模块,当然这里举例的&nbsp;http&nbsp;模块是&nbsp;Node.js&nbsp;内建的,所以无需单独安装;不过如果是非内建模块,这样安装:</p>
<div class="highlight">
<pre><code class="language-bash">npm install &lt;Module name&gt;</code></pre>
</div>
<p>接着,在安装了模块之后,我们就需要在开发项目当中引入该模块了。这个时候,Node.js&nbsp;会在我们应用中搜索是否存在&nbsp;node_modules&nbsp;的目录,并且搜索这个目录中是否存在模块;如果找不到这个目录,则会到全局模块缓存中去寻找,同时用户可以通过相对或者绝对路径,指定模块的位置,比如:</p>
<div class="highlight">
<pre><code class="language-js"><span class="kr">const <span class="nx">myModule <span class="o">= <span class="nx">require<span class="p">(<span class="s1">'./myModule.js'<span class="p">);</span></span></span></span></span></span></span></code></pre>
</div>
<h2>示例程序</h2>
<p>在我们创建&nbsp;Node.js&nbsp;第一个 "Hello, World!" 应用前,让我们先了解下&nbsp;Node.js&nbsp;应用是由哪几部分组成的:</p>
<ol>
<li>引入&nbsp;required&nbsp;模块:我们可以使用&nbsp;require&nbsp;指令来载入&nbsp;Node.js&nbsp;模块。</li>
<li>创建服务器:服务器可以监听客户端的请求,类似于&nbsp;Apache&nbsp;、Nginx&nbsp;等&nbsp;HTTP&nbsp;服务器。</li>
<li>接收请求与响应请求 服务器很容易创建,客户端可以使用浏览器或终端发送&nbsp;HTTP&nbsp;请求,服务器接收请求后返回响应数据。</li>
</ol>
<p>在项目的根目录下创建一个叫&nbsp;server.js&nbsp;的文件,并写入以下代码:</p>
<div class="cnblogs_code">
<pre>const http=require('http'<span style="color: rgba(0, 0, 0, 1)">)
http.createServer(</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(request,response){
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 发送 HTTP 头部 </span>
    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> HTTP 状态值: 200 : OK</span>
    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 内容类型: text/plain</span>
    response.writeHead(200,{'Content-Type':'text/plain'<span style="color: rgba(0, 0, 0, 1)">});
   
   </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 发送响应数据 "Hello World"</span>
    response.end('Hello World\n'<span style="color: rgba(0, 0, 0, 1)">);
}).listen(</span>8888<span style="color: rgba(0, 0, 0, 1)">);

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 终端打印如下信息</span>
console.log('Server running at http://127.0.0.1:8888/');</pre>
</div>
<p>运行: node server.js</p>
<p>接下来,打开浏览器访问&nbsp;<span class="invisible">http://<span class="visible">127.0.0.1:8888/</span></span>,就会看到一个写着“Hello World”的网页。</p>
<p>简要分析一下:</p>
<ul>
<li>这里引入了&nbsp;ef="<span class="invisible">http://<span class="visible">nodejs.cn/api/http.html</span></span>"&gt;HTTP 模块:使用该模块来创建 HTTP 服务器</li>
<li>服务器被设置为在指定的&nbsp;8888端口上进行监听, 当服务器就绪时,则&nbsp;listen&nbsp;回调函数会被调用【这里没有设置】。</li>
<li><span style="color: rgba(255, 0, 0, 1)">createServer传入的回调函数会在每次接收到请求时被执行</span>, 每当接收到新的请求时,"http://nodejs.cn/api/http.html#http_event_request"&gt;request 事件会被调用,并提供两个对象:一个请求(http.IncomingMessage&nbsp;对象)和一个响应(http.ServerResponse&nbsp;对象)</li>
<li>request&nbsp;提供了请求的详细信息, 通过它可以访问请求头和请求的数据,response&nbsp;用于构造要返回给客户端的数据;在此示例中:设置&nbsp;statusCode&nbsp;属性为&nbsp;200,以表明响应成功;还设置了&nbsp;Content-Type&nbsp;响应头;最后结束并关闭响应,将内容作为参数添加到&nbsp;end():</li>
</ul>
<h2>包管理器</h2>
<p>除了&nbsp;Node.js&nbsp;自带的&nbsp;NPM&nbsp;包管理器,还有一些比较常用的第三方包管理器,比如&nbsp;yarn(来自&nbsp;Facebook)或者&nbsp;bower&nbsp;等等。</p>
<p><span style="color: rgba(255, 0, 0, 1)">NPM&nbsp;是随同&nbsp;Node.js&nbsp;一起安装的包管理工具</span>,能解决其代码部署上的很多问题,常见的使用场景有以下几种:</p>
<ul>
<li>允许用户从&nbsp;NPM&nbsp;服务器下载别人编写的第三方包到本地使用。</li>
<li>允许用户从&nbsp;NPM&nbsp;服务器下载并安装别人编写的命令行程序到本地使用。</li>
<li>允许用户将自己编写的包或命令行程序上传到&nbsp;NPM&nbsp;服务器供别人使用。</li>
</ul>
<p>npm -v 查看版本</p>
<p>npm install npm -g 升级npm</p>
<p><strong>1、安装模块</strong></p>
<p>npm install &lt;Module Name&gt;&nbsp; 安装模块,</p>
<p>eg:npm install express</p>
<p>安装完后包就放在当前工程目录下的&nbsp;node_modules&nbsp;目录中,因此在代码中只需要通过&nbsp;require('express')&nbsp;的方式就好,无需指定第三方包路径:<code class="language-js"><span class="kr">const <span class="nx">express <span class="o">= <span class="nx">require<span class="p">(<span class="s1">'express'<span class="p">);</span></span></span></span></span></span></span></code></p>
<p><strong>2、全局安装(global)与本地安装(local)</strong></p>
<ul>
<li>npm install express # 本地安装</li>
<li>npm install express -g # 全局安装</li>
</ul>
<p>如果出现以下错误:npm err! Error: connect ECONNREFUSED 127.0.0.1:8087</p>
<p>解决办法为:npm config set proxy null</p>
<p><strong>本地安装</strong></p>
<ul>
<li>将安装包放在 ./node_modules 下(运行 npm 命令时所在的目录),如果没有 node_modules 目录,会在当前执行 npm 命令的目录下生成 node_modules 目录。</li>
<li>可以通过 require() 来引入本地安装的包。</li>
</ul>
<p><strong>全局安装</strong></p>
<ul>
<li>将安装包放在 /usr/local 下或者你 node 的安装目录【win环境中其实应该是 C:\Users\xxx\AppData\Roaming\npm\node_modules】。</li>
<li>可以直接在命令行里使用。</li>
</ul>
<p>如果你希望具备两者功能,则需要在两个地方安装它或使用 npm link。</p>
<p>接下来我们使用全局方式安装 express:npm install express -g</p>
<p><span style="font-size: 16px"><span style="color: rgba(255, 0, 0, 1)">可以使用自定义的路径去存储模块,参考&nbsp;</span>Node.js安装及环境配置之Windows篇~之环境变量配置</span></p>
<p>然后就可以直接引用全局模块了,eg:全局安装模块axios后,const axios = require('axios');。</p>
<p><strong>3、查看安装信息</strong></p>
<p>使用以下命令来查看所有全局安装的模块:npm list -g</p>
<p>如果要查看某个模块的版本号:npm list &lt;module name&gt;&nbsp;</p>
<p><strong>4、使用package.json</strong></p>
<p>package.json&nbsp;位于模块的目录下,用于定义包的属性。</p>
<p>Package.json 属性说明</p>
<ul>
<li>name:包名</li>
<li>version:包的版本号</li>
<li>description:包的描述</li>
<li>homepage:包的官网&nbsp;url</li>
<li>author:包的作者姓名</li>
<li>contributors:包的其他贡献者姓名</li>
<li>dependencies:依赖包列表;如果依赖包没有安装,NPM&nbsp;会自动将依赖包安装在&nbsp;node_module&nbsp;目录下</li>
<li>repository:包代码存放的地方的类型,可以是&nbsp;git&nbsp;或&nbsp;svn,git&nbsp;可在&nbsp;Github&nbsp;上</li>
<li>main:main&nbsp;字段指定了程序的主入口文件,require('moduleName')&nbsp;就会加载这个文件;这个字段的默认值是模块根目录下面的&nbsp;index.js</li>
<li>keywords&nbsp;- 关键字</li>
</ul>
<p><strong>5、其他命令</strong></p>
<p>卸载模块:npm uninstall module_name</p>
<p>更新模块:npm update module_name</p>
<p>搜索模块:npm search module_name</p>
<p>创建模块:npm init 生成package.json文件 (需要填写包的信息,注册用户,发布模块).......</p>
<p>查看所有命令:npm help&nbsp;</p>
<p>某条命令的帮助:npm help command_name</p>
<p><strong>6、运行</strong></p>
<p>两种方式</p>
<p>1、直接终端运行&nbsp; node xxx.js</p>
<p>2、添加start启动项</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">"scripts": {
    "test": "echo \"Error: no test specified\" &amp;&amp; exit 1",
    "start":"node service.js"
}</span></pre>
</div>
<p>再执行npm start&nbsp;</p>
<p><strong>7、版本号</strong></p>
<p>NPM&nbsp;使用语义版本号来管理代码,这里简单介绍一下。</p>
<p>语义版本号分为&nbsp;X.Y.Z&nbsp;三位,分别代表主版本号、次版本号和补丁版本号,当代码变更时,版本号按以下原则更新:</p>
<ul>
<li>如果只是修复&nbsp;bug,需要更新&nbsp;Z&nbsp;位。</li>
<li>如果是新增了功能,但是向下兼容,需要更新&nbsp;Y&nbsp;位。</li>
<li>如果有大变动,向下不兼容,需要更新&nbsp;X&nbsp;位。</li>
</ul>
<p>版本号有了这个保证后,在申明第三方包依赖时,除了可依赖于一个固定版本号外,还可依赖于某个范围的版本号,例如&nbsp;"argv": "0.0.x"&nbsp;表示依赖于&nbsp;0.0.x&nbsp;系列的最新版&nbsp;argv。</p>
<p><strong>8、使用淘宝NPM镜像</strong></p>
<p>大家都知道国内直接使用 npm 的官方镜像是非常慢的,在不涉及到“墙”的情况下,我们可以考虑使用淘宝 NPM 镜像。</p>
<p>淘宝 NPM 镜像(https://cnpmjs.org/)是一个完整 http://npmjs.org 镜像,可以用此代替官方版本(只读),同步频率目前为 10分钟一次以保证尽量与官方服务同步。</p>
<p>我个人比较喜欢使用淘宝定制的 cnpm(gzip 压缩支持)命令行工具代替默认的 npm:</p>
<p><span style="color: rgba(255, 0, 0, 1)">npm install -g cnpm --registry=https://registry.npm.taobao.org</span></p>
<p>这样就可以使用 cnpm 命令来安装模块了:</p>
<p>cnpm install <br>更多信息可以查阅:国内优秀npm镜像推荐及使用</p>
<h2>REPL</h2>
<p>REPL是Read Eval Print Loop&nbsp;的缩写,中文译名是<span style="color: rgba(255, 0, 0, 1)">交互式解释器</span>;其实说白了就是命令行的开发工具,这个也是&nbsp;Node.js&nbsp;的基础功能之一,使得我们可以不必借助浏览器环境,直接开发和运行一些无需&nbsp;GUI&nbsp;的程序,也就从很多方面上看起来更接近传统的开发语言环境。</p>
<p>它表示一个电脑的环境,类似&nbsp;Window&nbsp;系统的终端或&nbsp;Unix/Linux shell,我们可以在终端中输入命令,并接收系统的响应。</p>
<p>Node&nbsp;自带了交互式解释器,可以执行以下任务:</p>
<ul>
<li>读取&nbsp;- 读取用户输入,解析输入了&nbsp;JavaScript&nbsp;数据结构并存储在内存中</li>
<li>执行&nbsp;- 执行输入的数据结构</li>
<li>打印&nbsp;- 输出结果</li>
<li>循环&nbsp;- 循环操作以上步骤直到用户两次按下&nbsp;ctrl-c&nbsp;按钮退出</li>









</ul>
<p>Node&nbsp;的交互式解释器可以很好的调试&nbsp;JavaScript&nbsp;代码。</p>
<p>我们可以输入&nbsp;node&nbsp;命令来启动&nbsp;Node&nbsp;的终端。</p>
<p><strong>表达式计算</strong>:1+2</p>
<p><strong>使用变量</strong>:变量声明用var、let、const,使用&nbsp;console.log()&nbsp;来输出。</p>
<p><img src="https://img2020.cnblogs.com/blog/727485/202106/727485-20210618094747804-889660038.png" alt="" loading="lazy"></p>
<p><strong>下划线变量</strong>:&nbsp;可以使用下划线 _ 获取上一个表达式的运算结果:</p>
<p><img src="https://img2020.cnblogs.com/blog/727485/202106/727485-20210618095113747-1444792066.png" alt="" loading="lazy"></p>
<h2>包运行器~NPX</h2>
<p>NPX&nbsp;就是一个可以直接执行&nbsp;NPM&nbsp;当中发布的模块的命令,而无需提前下载安装;或者也可以直接调用项目内的模块,或者说本地模块;甚至可以运行完全不同版本的&nbsp;Node,这些都是它的强大之处。</p>
<ul>
<li>用NPM需要先下载模块,再使用;</li>
<li>用NPX则直接使用,npx&nbsp;会自动进行下载,执行该命令后再删除,比较适合需要一次性执行的任务。</li>









</ul>
<h2>事件循环</h2>
<p class="Post-Title">Node.js从零开始——事件循环</p>
<p>事件循环(Event Loop)是了解&nbsp;Node.js&nbsp;最重要的方面之一;它阐明了&nbsp;Node.js&nbsp;如何做到<span style="color: rgba(255, 0, 0, 1)">异步且具有非阻塞的&nbsp;I/O</span>,也就是&nbsp;Node.js&nbsp;的“杀手级应用”,正是这一点使它成功了。</p>
<p>和原生&nbsp;JavaScript&nbsp;一样,<span style="color: rgba(255, 0, 0, 1)">Node&nbsp;的代码也是运行在单线程上的, 每次只处理一件事</span>。</p>
<p>这个限制实际上非常有用,因为它大大简化了编程方式,而不必担心并发问题,只需要注意如何编写代码,并避免任何可能阻塞线程的事情,例如同步的网络调用或无限的循环。</p>
<p>通常,在大多数浏览器中,每个浏览器选项卡都有一个事件循环,以使每个进程都隔离开,并避免使用无限的循环或繁重的处理来阻止整个浏览器的网页。</p>
<p><span style="color: rgba(255, 0, 0, 1)">Node&nbsp;环境同理,它管理多个并发的事件循环,例如处理&nbsp;API&nbsp;调用、&nbsp;Web&nbsp;工作进程也运行在自己的事件循环中</span>,我们所要关注的重心,就在于如何确保自己的应用工作在单线程当中,而不会阻塞事件循环。</p>
<p><strong>阻塞事件循环</strong></p>
<p>任何花费太长时间才能将控制权返回给事件循环的&nbsp;JavaScript&nbsp;代码,都会阻塞页面中任何&nbsp;JavaScript&nbsp;代码的执行,甚至阻塞&nbsp;UI&nbsp;线程,并且用户无法单击浏览、滚动页面等。</p>
<p>JavaScript&nbsp;中几乎所有的&nbsp;I/O&nbsp;基元都是非阻塞的: 网络请求、文件系统操作等; 被阻塞是个异常,这就是&nbsp;JavaScript&nbsp;如此之多基于回调(当然打从 ES 6 发布之后,越来越多基于&nbsp;promise&nbsp;和&nbsp;async/await)的原因。</p>
<p><strong>调用堆栈</strong></p>
<p>调用堆栈是一个&nbsp;LIFO&nbsp;队列(后进先出):事件循环不断地检查调用堆栈,以查看是否需要运行任何函数,当执行时,它会将找到的所有函数调用添加到调用堆栈中,并按顺序执行每个函数。</p>
<p><strong>让一个函数执行插队</strong></p>
<p>setTimeout(() =&gt; {}, 0)&nbsp;就是个典型的在代码中其他函数执行之后,再调用一个函数的用法。</p>
<p><strong>消息队列</strong></p>
<p>当调用&nbsp;setTimeout()&nbsp;时,浏览器或&nbsp;Node.js&nbsp;会启动定时器, 当定时器到期时(在此示例中会立即到期,因为将超时值设为&nbsp;0),则<span style="color: rgba(255, 0, 0, 1)">回调函数会被放入“消息队列”中</span>。</p>
<p>在消息队列中,用户触发的事件(如单击或键盘事件、或获取响应)也会在此排队,然后代码才有机会对其作出反应;类似&nbsp;onLoad&nbsp;这样的&nbsp;DOM&nbsp;事件也如此。</p>
<p><span style="color: rgba(255, 0, 0, 1)">事件循环会赋予调用堆栈优先级,它首先处理在调用堆栈中找到的所有东西,一旦其中没有任何东西,便开始处理消息队列中的东西</span>。</p>
<p>我们不必等待诸如&nbsp;setTimeout、fetch&nbsp;或其他的函数来完成它们自身的工作,因为它们是由浏览器提供的,并且位于它们自身的线程中。</p>
<p><strong>process.nextTick()</strong></p>
<p>每当事件循环进行一次完整的行程时,我们都将其称为一个滴答。</p>
<p>当将一个函数传给&nbsp;process.nextTick()&nbsp;时,则指示引擎在当前操作结束(在下一个事件循环滴答开始之前)时调用此函数:</p>
<div class="highlight">
<pre><code class="language-js"><span class="nx">process<span class="p">.<span class="nx">nextTick<span class="p">(() <span class="p">=&gt; <span class="p">{
<span class="c1">//做些事情
<span class="c1"><span class="p">});
</span></span></span></span></span></span></span></span></span></code></pre>
</div>
<p>事件循环正在忙于处理当前的函数代码,当该操作结束时,JS 引擎会运行在该操作期间传给&nbsp;nextTick&nbsp;调用的所有函数;这是可以告诉&nbsp;JS&nbsp;引擎异步地(在当前函数之后)处理函数的方式,但是尽快执行而不是将其排入队列。</p>
<p>调用&nbsp;setTimeout(() =&gt; {}, 0)&nbsp;会在下一个滴答结束时执行该函数,比使用&nbsp;nextTick()(其会优先执行该调用并在下一个滴答开始之前执行该函数)晚得多。</p>
<p><span style="color: rgba(255, 0, 0, 1)">当要确保在下一个事件循环迭代中代码已被执行,则需要使用&nbsp;nextTick()</span>。</p>
<p><strong>setImmediate()</strong></p>
<p>当要异步地(但要尽可能快)执行某些代码时,其中一个选择是使用&nbsp;Node.js&nbsp;提供的&nbsp;setImmediate()&nbsp;函数:</p>
<div class="highlight">
<pre><code class="language-js"><span class="nx">setImmediate<span class="p">(() <span class="p">=&gt; <span class="p">{
<span class="c1">//运行一些东西
<span class="c1"><span class="p">});
</span></span></span></span></span></span></span></code></pre>
</div>
<p>作为&nbsp;setImmediate()&nbsp;参数传入的任何函数都是在事件循环的下一个迭代中执行的回调。</p>
<p>setImmediate()&nbsp;与&nbsp;setTimeout(() =&gt; {}, 0)(传入&nbsp;0&nbsp;毫秒的延时)、process.nextTick()&nbsp;有何不同?</p>
<ul>
<li>传给&nbsp;process.nextTick()&nbsp;的函数会在事件循环的当前迭代中(当前操作结束之后)被执行; 这意味着它会始终在&nbsp;setTimeout&nbsp;和&nbsp;setImmediate&nbsp;之前执行。</li>
<li>延迟&nbsp;0&nbsp;毫秒的&nbsp;setTimeout()&nbsp;回调与&nbsp;setImmediate()&nbsp;非常相似; 执行顺序取决于各种因素,但是它们都会在事件循环的下一个迭代中运行。</li>
</ul>
<h2>异步编程与回调</h2>
<p class="asset-name entry-title">参考:Node.js从零开始——异步编程与回调</p>
<p id="page-title" class="asset-name entry-title">Javascript异步编程的4种方法</p>
<ul>
<li>回调函数</li>
<li>事件监听</li>
<li>发布/订阅</li>
<li>Promise对象</li>
</ul>
<p><strong>Javascript的异步性</strong></p>
<p>JavaScript&nbsp;默认情况下是同步的,并且是单线程的,这意味着代码无法创建新的线程并且不能并行运行。</p>
<p>但是&nbsp;JavaScript&nbsp;诞生于浏览器内部,一开始的主要工作是响应用户的操作,例如&nbsp;onClick、onMouseOver、onChange、onSubmit&nbsp;等,使用同步的编程模型该如何做到这一点?</p>
<p>答案就在于它的环境: <span style="color: rgba(255, 0, 0, 1)">浏览器通过提供一组可以处理这种功能的&nbsp;API&nbsp;来提供了一种实现方式</span>。【回调】</p>
<p>而在&nbsp;Node.js&nbsp;这里,引入了非阻塞的&nbsp;I/O&nbsp;环境,以将该概念扩展到文件访问、网络调用等。</p>
<p><strong>回调</strong></p>
<p>我们不知道用户何时单击按钮,因此,为点击事件定义了一个事件处理程序,该事件处理程序会接受一个函数,该函数会在该事件被触发时被调用:</p>
<div class="highlight">
<pre><code class="language-js"><span class="nb">document<span class="p">.<span class="nx">getElementById<span class="p">(<span class="s1">'button'<span class="p">).<span class="nx">addEventListener<span class="p">(<span class="s1">'click'<span class="p">, <span class="p">() <span class="p">=&gt; <span class="p">{
<span class="c1">//被点击
<span class="c1"><span class="p">});
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
</div>
<p>这就是所谓的回调。</p>
<p>回调是一个简单的函数,会作为值被传给另一个函数,并且仅在事件发生时才被执行; 之所以这样做,是因为&nbsp;JavaScript&nbsp;具有顶级的函数,这些函数可以被分配给变量并传给其他函数(称为高阶函数)。</p>
<p><strong>回调的替代方法</strong></p>
<p>从&nbsp;ES 6&nbsp;开始,JavaScript&nbsp;引入了一些特性,<span style="color: rgba(255, 0, 0, 1)">可以帮助处理异步代码而不涉及使用回调:Promise(ES 6)和&nbsp;Async/Await(ES 2017),都是非常好的替代方式,这样回调可以修改成更为直观的链式操作</span>,譬如上面的例子:</p>
<div class="cnblogs_code">
<pre>$.get('https://www.bing.com'<span style="color: rgba(0, 0, 0, 1)">)
.done( () </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 操作</span>
}).fail( () =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 报错操作</span>
});</pre>
</div>
<p>再比如&nbsp;Promise&nbsp;的例子(当然是很简单的例子):</p>
<div class="cnblogs_code">
<pre>const myPromise = <span style="color: rgba(0, 0, 255, 1)">new</span> Promise((resolve, reject) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
resolve(</span>'done'<span style="color: rgba(0, 0, 0, 1)">);
reject(</span>'error'<span style="color: rgba(0, 0, 0, 1)">);
});

myPromise.then(value </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> {
console.log(value);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> expected output: "foo"</span>
});</pre>
</div>
<h3>Promise简介</h3>
<p>Promise&nbsp;通常被定义为最终会变为可用值的代理,它是一种处理异步代码(而不会陷入Callback Hell&nbsp; &nbsp;回调地狱)的方式。</p>
<p>异步函数(&nbsp;async&nbsp;和&nbsp;await)在底层使用了&nbsp;promise,因此了解&nbsp;promise&nbsp;的工作方式是了解&nbsp;async&nbsp;和&nbsp;await&nbsp;的基础。</p>
<p><strong>Promise如何运作</strong></p>
<p>当&nbsp;promise&nbsp;被调用后,它会以<span style="color: rgba(255, 0, 0, 1)">处理中状态</span>开始; 这意味着调用的函数会继续执行,而&nbsp;promise&nbsp;仍处于处理中直到解决为止,从而为调用的函数提供所请求的任何数据。</p>
<p>被创建的&nbsp;promise&nbsp;最终会以<span style="color: rgba(255, 0, 0, 1)">被解决状态【resolve】</span>或<span style="color: rgba(255, 0, 0, 1)">被拒绝状态【reject】</span>结束,并在完成时<span style="color: rgba(255, 0, 0, 1)">调用相应的回调函数(传给&nbsp;then&nbsp;和&nbsp;catch)</span>。</p>
<p><strong>创建Promise</strong></p>
<p>Promise API&nbsp;公开了一个&nbsp;Promise&nbsp;构造函数,可以使用&nbsp;new Promise()&nbsp;对其进行初始化:</p>
<div class="cnblogs_code">
<pre>const done = <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;

const isItDoneYet </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> Promise((resolve, reject) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (done) {
    const workDone </span>= '这是创建的东西'<span style="color: rgba(0, 0, 0, 1)">;
    resolve(workDone);
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
    const why </span>= '仍然在处理其他事情'<span style="color: rgba(0, 0, 0, 1)">;
    reject(why);
}
});</span></pre>
</div>
<p>这里&nbsp;promise&nbsp;检查了&nbsp;done&nbsp;全局常量,如果为真,则&nbsp;promise&nbsp;进入被解决状态(因为调用了&nbsp;resolve&nbsp;回调);否则,则执行&nbsp;reject&nbsp;回调(将&nbsp;promise&nbsp;置于被拒绝状态);如果在执行路径中从未调用过这些函数之一,则&nbsp;promise&nbsp;会保持处理中状态。</p>
<p>使用&nbsp;resolve&nbsp;和&nbsp;reject,可以向调用者传达最终的&nbsp;promise&nbsp;状态以及该如何处理;在上面的例子中,只返回了一个字符串,但是它可以是一个对象,也可以为&nbsp;null;</p>
<p>一个更常见的示例是一种被称为&nbsp;<span style="color: rgba(255, 0, 0, 1)">Promisifying&nbsp;</span>的技术,这项技术能够使用经典的&nbsp;JavaScript&nbsp;函数来接受回调并使其返回&nbsp;promise(就是&nbsp;return new Promise()):</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_0343dcc6-045d-46dd-8722-22d46c71cc32" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_0343dcc6-045d-46dd-8722-22d46c71cc32" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_0343dcc6-045d-46dd-8722-22d46c71cc32" class="cnblogs_code_hide">
<pre>const fs = require('fs'<span style="color: rgba(0, 0, 0, 1)">);

const getFile </span>= fileName =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Promise((resolve, reject) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
    fs.readFile(fileName, (err, data) </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> {
      </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (err) {
      reject (err);</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 调用 reject 会导致 promise 失败,无论是否传入错误作为参数,</span>
      <span style="color: rgba(0, 0, 255, 1)">return</span>;      <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 且不再进行下去。</span>
<span style="color: rgba(0, 0, 0, 1)">      }
      resolve(data);
    });
});
};

getFile(</span>'/etc/passwd'<span style="color: rgba(0, 0, 0, 1)">)
.then(data </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> console.log(data))
.</span><span style="color: rgba(0, 0, 255, 1)">catch</span>(err =&gt; console.error(err));</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<h3>async/await</h3>
<p>JavaScript&nbsp;在很短的时间内从回调发展到了&nbsp;promise(ES 6&nbsp;或者&nbsp;ES 2015),且自&nbsp;ES 2017&nbsp;以来,异步的&nbsp;JavaScript&nbsp;使用&nbsp;async/await&nbsp;语法甚至更加简单。</p>
<p>异步函数是&nbsp;promise&nbsp;和生成器的组合,基本上,它们是&nbsp;promise&nbsp;的更高级别的抽象; 而<span style="color: rgba(255, 0, 0, 1)">&nbsp;async/await&nbsp;建立在&nbsp;promise&nbsp;之上,</span>减少了&nbsp;promises&nbsp;自身的语法复杂性,且减少了&nbsp;promise&nbsp;链的“不破坏链条”的限制</p>
<p>当&nbsp;ES 6&nbsp;中引入&nbsp;Promise&nbsp;时,本来旨在解决异步代码的问题,并且确实做到了,但是很明显,promise&nbsp;不可能成为最终的解决方案:Promise&nbsp;反而引入了语法复杂性。</p>
<p>故而在&nbsp;ES 2017&nbsp;当中,async/await&nbsp;出现了,它们可以向开发人员提供更容易理解和更简洁的语法,它们使代码看起来像是同步的,但实际上是异步的并且在后台无阻塞。</p>
<p><strong>简单示例</strong></p>
<div class="cnblogs_code">
<pre>const aFunction = async () =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> '测试'<span style="color: rgba(0, 0, 0, 1)">;
};

aFunction().then(alert);</span></pre>
</div>
<p>在任何函数之前加上&nbsp;async&nbsp;关键字意味着该函数会返回&nbsp;promise;即使没有显式地这样做,它也会在内部返回&nbsp;promise。</p>
<div class="cnblogs_code">
<pre>const aFunction = async () =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> Promise.resolve('测试'<span style="color: rgba(0, 0, 0, 1)">);
};

aFunction().then(alert);</span></pre>
</div>
<p><strong>代码更容易阅读</strong></p>
<p>例如,这是使用&nbsp;promise&nbsp;获取并解析&nbsp;JSON&nbsp;资源的方法:</p>
<div class="cnblogs_code">
<pre>const getFirstUserData = () =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> fetch('/users.json') <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取用户列表</span>
    .then(response =&gt; response.json()) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 解析 JSON</span>
    .then(users =&gt; users) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 选择第一个用户</span>
    .then(user =&gt; fetch(`/users/${user.name}`)) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取用户数据</span>
    .then(userResponse =&gt; userResponse.json()); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 解析 JSON</span>
<span style="color: rgba(0, 0, 0, 1)">};

getFirstUserData();</span></pre>
</div>
<p>这是使用&nbsp;await/async&nbsp;提供的相同功能:</p>
<div class="cnblogs_code">
<pre>const getFirstUserData = async () =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
const response </span>= await fetch('/users.json'); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取用户列表</span>
const users = await response.json(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 解析 JSON</span>
const user = users; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 选择第一个用户</span>
const userResponse = await fetch(`/users/${user.name}`); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取用户数据</span>
const userData = await userResponse.json(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 解析 JSON</span>
<span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> userData;
}

getFirstUserData();</span></pre>
</div>
<p>看起来后者更像是同步的代码,仅仅是多增加了&nbsp;await&nbsp;命令,这样对编程人员来说更容易理解,也更不容易出错。</p>
<h2>组件</h2>
<h3>HTTP服务器</h3>
<p>其实&nbsp;Node.js&nbsp;最初的目的,就是实现一个完全可以由&nbsp;JavaScript&nbsp;来进行开发的服务器端,所以归根到底,它的后端能力之一就是实现一个&nbsp;HTTP&nbsp;服务器,</p>
<p>见 示例程序</p>
<p><strong>使用Node.js发送Http请求</strong></p>
<p>get请求</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_223d245a-4340-4e17-84dc-977edfa6d117" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_223d245a-4340-4e17-84dc-977edfa6d117" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_223d245a-4340-4e17-84dc-977edfa6d117" class="cnblogs_code_hide">
<pre>const https = require('http'<span style="color: rgba(0, 0, 0, 1)">);
const options </span>=<span style="color: rgba(0, 0, 0, 1)"> {
hostname: </span>'127.0.0.1'<span style="color: rgba(0, 0, 0, 1)">,
port: </span>3000<span style="color: rgba(0, 0, 0, 1)">,
path: </span>'/'<span style="color: rgba(0, 0, 0, 1)">,
method: </span>'GET'<span style="color: rgba(0, 0, 0, 1)">
};

const req </span>= https.request(options, res =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
console.log(`状态码: ${res.statusCode}`);

res.on(</span>'data', d =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
    process.stdout.write(d);
});
});

req.on(</span>'error', error =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
console.error(error);
});

req.end();</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>Post请求</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_33532aa0-da8b-4aa3-be78-2cb5028597ce" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_33532aa0-da8b-4aa3-be78-2cb5028597ce" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_33532aa0-da8b-4aa3-be78-2cb5028597ce" class="cnblogs_code_hide">
<pre>const https = require('http'<span style="color: rgba(0, 0, 0, 1)">);

const data </span>=<span style="color: rgba(0, 0, 0, 1)"> JSON.stringify({
todo: </span>'做点事情'<span style="color: rgba(0, 0, 0, 1)">
});

const options </span>=<span style="color: rgba(0, 0, 0, 1)"> {
hostname: </span>'127.0.0.1'<span style="color: rgba(0, 0, 0, 1)">,
port: </span>3000<span style="color: rgba(0, 0, 0, 1)">,
path: </span>'/'<span style="color: rgba(0, 0, 0, 1)">,
method: </span>'POST'<span style="color: rgba(0, 0, 0, 1)">,
headers: {
    </span>'Content-Type': 'application/json'<span style="color: rgba(0, 0, 0, 1)">,
    </span>'Content-Length'<span style="color: rgba(0, 0, 0, 1)">: data.length
}
};

const req </span>= https.request(options, res =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
console.log(`状态码: ${res.statusCode}`);

res.on(</span>'data', d =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
    process.stdout.write(d);
});
});

req.on(</span>'error', error =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
console.error(error);
});

req.write(data);
req.end();</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p><strong>使用Axios发送Http请求</strong></p>
<p>在&nbsp;Node.js&nbsp;中,有多种方式可以执行&nbsp;HTTP POST&nbsp;请求,具体取决于要使用的抽象级别。</p>
<p>使用&nbsp;Node.js&nbsp;执行&nbsp;HTTP&nbsp;请求的最简单的方式是使用&nbsp;f="<span class="invisible">https://<span class="visible">github.com/axios/axios</span></span>"&gt;Axios 库(多嘴说一句,<span style="color: rgba(255, 0, 0, 1)">Vue.js&nbsp;推荐使用的也是这个库</span>):</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_cb0f9bbf-694f-41a3-82dd-d1cbd600c940" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_cb0f9bbf-694f-41a3-82dd-d1cbd600c940" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_cb0f9bbf-694f-41a3-82dd-d1cbd600c940" class="cnblogs_code_hide">
<pre>const axios = require('axios'<span style="color: rgba(0, 0, 0, 1)">);

axios
.post(</span>'http://nodejs.cn/todos'<span style="color: rgba(0, 0, 0, 1)">, {
    todo: </span>'做点事情'<span style="color: rgba(0, 0, 0, 1)">
})
.then(res </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> {
    console.log(`状态码: ${res.statusCode}`);
    console.log(res);
})
.</span><span style="color: rgba(0, 0, 255, 1)">catch</span>(error =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
    console.error(error);
});</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>Axios&nbsp;是第三方的库,所以需要通过包管理器先进行安装。</p>
<p><strong>HTTP模块</strong></p>
<p>HTTP&nbsp;核心模块是&nbsp;Node.js&nbsp;网络的关键模块。</p>
<p>方法:</p>
<p>(1)http.createServer()</p>
<p>返回&nbsp;http.Server&nbsp;类的新实例。</p>
<div class="cnblogs_code">
<pre>const server = http.createServer((req, res) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">使用此回调处理每个单独的请求</span>
})</pre>
</div>
<p>(2)http.request()</p>
<p>发送&nbsp;HTTP&nbsp;请求到服务器,并创建&nbsp;http.ClientRequest&nbsp;类的实例。</p>
<p>(3)http.get()</p>
<p>类似于&nbsp;http.request(),但会自动地设置&nbsp;HTTP&nbsp;方法为&nbsp;GET,并自动地调用&nbsp;req.end()。</p>
<p>类:</p>
<p>HTTP&nbsp;模块提供了&nbsp;5&nbsp;个类:</p>
<ul>
<li>http.Agent</li>
<li>http.ClientRequest</li>
<li>http.Server</li>
<li>http.ServerResponse</li>
<li>http.IncomingMessage</li>
</ul>
<h3>文件系统</h3>
<p class="Post-Title">Node.js从零开始——文件系统</p>
<p><strong>1、fs 模块</strong></p>
<p>提供了许多非常实用的函数来访问文件系统并与文件系统进行交互,它作为 Node.js 核心的组成部分,无需安装,可以通过简单地引用来使用它:</p>
<pre><code class="language-js"><span class="kr">const <span class="nx">fs <span class="o">= <span class="nx">require<span class="p">(<span class="s1">'fs'<span class="p">);</span></span></span></span></span></span></span></code></pre>
<ul>
<li>fs.access():检查文件是否存在,以及&nbsp;Node.js&nbsp;是否有权限访问</li>
<li>fs.appendFile():追加数据到文件,如果文件不存在,则创建文件</li>
<li>fs.chmod(): 更改文件(通过传入的文件名指定)的权限,相关方法:fs.lchmod()、fs.fchmod()</li>
<li>fs.chown():更改文件(通过传入的文件名指定)的所有者和群组,相关方法:fs.fchown()、fs.lchown()</li>
<li>fs.close():关闭文件描述符</li>
<li>fs.copyFile():拷贝文件</li>
<li>fs.createReadStream():创建可读的文件流</li>
<li>fs.createWriteStream():创建可写的文件流</li>
<li>fs.link():新建指向文件的硬链接</li>
<li>fs.mkdir():新建文件夹</li>
<li>fs.mkdtemp():创建临时目录</li>
<li>fs.open():设置文件模式</li>
<li>fs.readdir():读取目录的内容</li>
<li><span style="color: rgba(255, 0, 0, 1)">fs.readFile():读取文件的内容</span>,相关方法:fs.read()</li>
<li>fs.readlink():读取符号链接的值</li>
<li>fs.realpath():将相对的文件路径指针(.、..)解析为完整的路径</li>
<li>fs.rename():重命名文件或文件夹</li>
<li>fs.rmdir():删除文件夹</li>
<li>fs.stat():返回文件(通过传入的文件名指定)的状态,相关方法:fs.fstat()、fs.lstat()</li>
<li>fs.symlink():新建文件的符号链接</li>
<li>fs.truncate():将传递的文件名标识的文件截断为指定的长度,相关方法:fs.ftruncate()</li>
<li>fs.unlink():删除文件或符号链接</li>
<li>fs.unwatchFile():停止监视文件上的更改</li>
<li>fs.utimes():更改文件(通过传入的文件名指定)的时间戳,相关方法:fs.futimes()</li>
<li>fs.watchFile():开始监视文件上的更改,相关方法:fs.watch()</li>
<li><span style="color: rgba(255, 0, 0, 1)">fs.writeFile():将数据写入文件</span>,相关方法:fs.write()</li>
</ul>
<p>关于&nbsp;fs&nbsp;模块的特殊之处是,所有的方法默认情况下都是异步的,但是通过加上&nbsp;Sync&nbsp;后缀也可以同步地工作。<br>例如:</p>
<ul>
<li>fs.rename()</li>
<li>fs.renameSync()</li>
<li>fs.write()</li>
<li>fs.writeSync()</li>




</ul>
<p><strong>2、path模块</strong>&nbsp;</p>
<p>提供了许多非常实用的函数来访问文件系统并与文件系统进行交互,同样作为&nbsp;Node.js&nbsp;核心的组成部分,也是无需安装的。&nbsp;</p>
<p>该模块提供了&nbsp;path.sep(作为路径段分隔符,在&nbsp;Windows&nbsp;上是&nbsp;\,在&nbsp;Linux/macOS&nbsp;上是&nbsp;/)和&nbsp;path.delimiter(作为路径定界符,在&nbsp;Windows&nbsp;上是&nbsp;;,在&nbsp;Linux/macOS&nbsp;上是&nbsp;:)。</p>
<h2>事件触发、操作系统、流</h2>
<p>因为我们之前在浏览器中使用&nbsp;JavaScript,所以知道&nbsp;JS&nbsp;通过事件处理了许多用户的交互:鼠标的单击、键盘按钮的按下、对鼠标移动的反应等等。</p>
<p>在后端,Node.js&nbsp;也提供了使用&nbsp;events 模块&nbsp;构建类似系统的选项。</p>
<p>具体上,此模块提供了&nbsp;EventEmitter&nbsp;类,用于处理事件。</p>
<p>使用以下代码进行初始化:</p>
<div class="cnblogs_code">
<pre>const EventEmitter = require('events'<span style="color: rgba(0, 0, 0, 1)">);
const eventEmitter </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> EventEmitter();</pre>
</div>
<p>该对象公开了&nbsp;on&nbsp;和&nbsp;emit&nbsp;方法:</p>
<ul>
<li>emit&nbsp;用于触发事件</li>
<li>on&nbsp;用于添加回调函数(会在事件被触发时执行)</li>
</ul>
<p>例如,创建&nbsp;start&nbsp;事件,并提供一个示例,通过记录到控制台进行交互:</p>
<div class="cnblogs_code">
<pre>eventEmitter.on('start', () =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
console.log(</span>'开始'<span style="color: rgba(0, 0, 0, 1)">);
});
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">当运行以下代码时:事件处理函数会被触发,且获得控制台日志。</span>
eventEmitter.emit('start');</pre>
</div>
<p>通过将参数作为额外参数传给&nbsp;emit()&nbsp;来将参数传给事件处理程序,以下是两个参数的示例:</p>
<div class="cnblogs_code">
<pre>eventEmitter.on('start', (start, end) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
console.log(`从 ${start} 到 ${end}`);
});
eventEmitter.emit(</span>'start', 1, 100);</pre>
</div>
<p>&nbsp;</p>
<h2>更多参考</h2>
<p>七天学会NodeJS</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/peterYong/p/14894717.html
頁: [1]
查看完整版本: Node.js学习