Node.js是一种开源、跨平台的 JavaScript 运行时环境,可在 Web 浏览器之外执行 JavaScript 代码。Node.js 是一种流行的、适合初学者的轻量级 Web 框架,许多大公司都在使用它,例如 Netflix 和 Uber。
当我们通常想到 JavaScript 时,我们的思绪往往会转到 Web 开发。在 Node.js 出现之前,真的没有办法在浏览器之外运行 JavaScript。当我们编写后端服务器和数据库时,Node.js 是一个流行的选择,因为我们可以将我们的代码作为一个独立的应用程序运行,而不是只能在浏览器环境中评估的东西。
Node.js 是任何 JavaScript 开发人员都需要了解的重要工具。所以,今天,我们将向您介绍 Node.js,并向您展示如何开始一个项目。
什么是 Node.js?
Node.js 是一种开源、跨平台的 JavaScript 运行时环境,用于在 Web 浏览器之外执行 JavaScript 代码。
Node.js 对于初学者来说是一个很棒的 Web 框架,因为它非常适合数据密集型应用程序,例如流媒体和实时应用程序,并且 Node.js 可以轻松开始构建后端。
Node.js 允许我们在任何地方和任何浏览器上使用 JavaScript,包括 macOS、Linux 和 Windows。当我们说无处不在时,我们指的是前端、中间件和后端。因此,Node.js 是一些非常流行的 Web 开发堆栈的一部分,例如 MERN 堆栈、MEVN 堆栈和 MEAN 堆栈。
有许多特性使 Node.js 成为现在的样子:
- Google Chrome V8 JavaScript 引擎: 此运行时环境基于 Google Chrome V8 JavaScript 运行时引擎构建。同样,Java 虚拟机翻译字节码,而 Chrome V8 JavaScript 引擎采用 JavaScript 并使其可读。
- 模块/包: Node.js 有 npm,一个节点包管理器,拥有超过 350,000 个包的库,可帮助您高效轻松地启动项目或应用程序。
- 事件驱动的单线程 I/O 模型: JavaScript 依赖于用户交互或事件来运行。在大多数情况下,代码是同步运行的。服务器请求和其他此类异步任务依赖于承诺系统或异步/等待函数来处理这些输入和输出。
Node.js 基础知识
现在我们知道了 Node.js 是什么,让我们来探索这个工具的基础知识。
控制台
控制台是 Node.js 提供的一个模块,当您检查网页时 , 它类似于浏览器中的 JavaScript 控制台。控制台具有可供我们用于调试目的的方法。
console.log()
:经常用于记录某种输出。console.warn()
:明确向控制台发出警告。console.error()
: 明确地向控制台发送一条错误消息。您可以将错误记录为字符串或对象。如果记录为新的Error()
,回溯将作为消息的一部分包含在内。console.trace()
:在代码中发生错误时记录回溯。给出可能发生错误的文件的行号和列号。
Buffer
Node.js 中的Buffer 类的核心是文件系统的临时存储解决方案。由于其低级特性,作为 Web 开发人员,我们很少会真正直接使用 Buffer 类。这个类的主要目的是分配内存。
下面我们就来看看Buffer类提供的几个方法。
const buf1 = Buffer.alloc(10); console.log(buf1); const buf2 = Buffer.alloc(5, 15); console.log(buf2); const buf3 = Buffer.allocUnsafe(10); console.log(buf3); buf3.fill(1); console.log(buf3); buf2.write("abcedf"); console.log(buf2); const buf4 = Buffer.from([265, 6.5, -255, '7']); console.log(buf4); const buf5 = Buffer.from('Hello world'); console.log(buf5); console.log(buf5.toString()); 复制代码
文件系统
文件系统 (fs) 模块允许我们与 Node.js 中的文件进行交互。有同步和异步方法可用于使用 fs 模块读取或写入文件。与使用控制台或 Buffer 类相比,我们需要将 fs 模块导入到我们想要使用的文件中才能使其工作。
下面的代码示例显示了readFile
异步方法的工作原理。请注意,该方法中的最后一个参数是一个回调函数,其第一个参数是一个错误。根据定义,此回调将始终在传递数据之前先传递错误。
异步示例:
该readFile
方法的异步特性不会阻止其他函数或代码行运行。
但是,同步方法readFileSync
会阻止其他代码行运行,直到文件读取完毕。
这是一个例子:
const fs = require('fs') fs.readFile('data.txt', 'utf-8', (err, data) => { if (err) { console.error(err) return } let array = data.split('\n') //props are id, first_name, last_name, email, gender and ip_address let mapped = array.map(person => { let new_person = person.split(','); return new Object({ id: new_person[0], first_name: new_person[1], last_name: new_person[2], email: new_person[3], gender: new_person[4], ip: new_person[5] }) }); console.log(mapped) }); console.log("Hit!") 复制代码
同步示例:
const fs = require('fs') try { const data = fs.readFileSync('data.txt', 'utf-8') let array = data.split('\n') //props are id, first_name, last_name, email, gender and ip_address let mapped = array.map(person => { let new_person = person.split(','); return new Object({ id: new_person[0], first_name: new_person[1], last_name: new_person[2], email: new_person[3], gender: new_person[4], ip: new_person[5] }) }); console.log(mapped) } catch (err) { console.error(err) } console.log("Hit!") 复制代码
数据.txt:
1,Annabell,Cicconetti,acicconetti0@example.com,Female,219.207.16.2 2,Silvana,Glasman,sglasman1@house.gov,Female,233.214.135.18 3,Rebeka,Redmile,rredmile2@utexas.edu,Female,121.106.165.14 4,Veriee,Jovis,vjovis3@japanpost.jp,Female,43.217.63.173 5,Melitta,Hanburry,mhanburry4@aboutads.info,Female,42.204.168.27 6,Alethea,Webben,awebben5@hatena.ne.jp,Female,189.126.43.49 7,Saxe,Leary,sleary6@behance.net,Male,95.156.25.21 8,Ario,Brabyn,abrabyn7@pcworld.com,Male,220.226.164.176 9,Marybeth,Ughelli,mughelli8@mit.edu,Female,251.234.218.207 10,Gothart,Tassell,gtassell9@freewebs.com,Male,247.146.121.230 11,Fairlie,Beevis,fbeevisa@stanford.edu,Male,161.219.190.148 12,Skippie,Station,sstationb@wikipedia.org,Male,178.184.167.113 13,Ashla,Tett,atettc@nature.com,Female,209.125.39.161 14,Belinda,Olin,bolind@discovery.com,Female,222.234.181.134 15,Laurianne,Ledgerton,lledgertone@google.co.uk,Female,184.56.226.2 16,Angele,Rhodus,arhodusf@ca.gov,Female,112.66.128.23 17,Meridith,Pena,mpenag@biblegateway.com,Female,163.227.38.120 18,Romola,Erbe,rerbeh@networksolutions.com,Female,184.50.183.25 19,Damien,Cominotti,dcominottii@naver.com,Male,122.62.139.51 20,Lou,Clemerson,lclemersonj@sfgate.com,Female,176.117.18.82 21,Donall,Lorence,dlorencek@shutterfly.com,Male,153.209.179.90 22,Maribeth,Sloam,msloaml@cbslocal.com,Female,177.119.164.156 23,Fowler,Pethybridge,fpethybridgem@vinaora.com,Male,58.228.162.249 24,Jarred,Haxley,jhaxleyn@ox.ac.uk,Male,26.74.46.200 25,Natalie,Outright,noutrighto@businessinsider.com,Female,181.218.16.217 26,Cloe,Devitt,cdevittp@gmpg.org,Female,109.68.184.211 27,Shane,Farmer,sfarmerq@ucsd.edu,Male,198.230.29.69 28,Iorgo,Thrower,ithrowerr@nsw.gov.au,Male,103.213.212.70 29,Letty,Dakhno,ldakhnos@pagesperso-orange.fr,Female,32.245.196.9 30,Woodrow,Flageul,wflageult@nsw.gov.au,Male,105.129.139.220 31,Franchot,Large,flargeu@statcounter.com,Male,219.98.60.51 32,Anna-diana,Callam,acallamv@51.la,Female,59.121.52.69 33,Benoit,Scallon,bscallonw@etsy.com,Male,227.53.63.103 34,Lavinie,Lovelady,lloveladyx@constantcontact.com,Female,227.20.131.192 35,Timoteo,Laurentino,tlaurentinoy@techcrunch.com,Male,149.251.44.30 36,Robers,Cassella,rcassellaz@google.pl,Male,179.219.60.199 37,Arnoldo,Eakly,aeakly10@live.com,Male,189.110.238.26 38,Janis,Didball,jdidball11@shinystat.com,Female,105.74.199.165 复制代码
console.log(“Hit!”)
尝试在函数之后放置一个以查看实际记录控制台的时间。这两个功能之间有区别吗?它是什么?
该readFile
函数将启动函数,然后在函数完成并打印出数组内容之前立即移动到其余代码。所以,你应该看到这样的东西:
Hit! [ { id: '1', first_name: 'Annabell', last_name: 'Cicconetti', email: 'acicconetti0@example.com', gender: 'Female', ip: '219.207.16.2' }, etc… ] 复制代码
相反,console.log(“Hit!”)
直到readFileSync
函数完成后才会运行:
[...{ id: '37', first_name: 'Arnoldo', last_name: 'Eakly', email: 'aeakly10@live.com', gender: 'Male', ip: '189.110.238.26' }, { id: '38', first_name: 'Janis', last_name: 'Didball', email: 'jdidball11@shinystat.com', gender: 'Female', ip: '105.74.199.165' } ] Hit! 复制代码
写入文件的方式非常相似,但调用的函数是writeFile()
和writeFileSync()
。
事件循环
许多 Node.js 被构建为事件驱动的。当用户单击界面或在表单中键入时,将触发事件发生,然后发生某些结果。将一个函数或一组函数附加到特定事件就是发出一个事件。
这些函数称为事件侦听器,是称为事件循环的整个旅程的一部分。举个例子:
const EventEmitter = require('events'); const emitter = new EventEmitter(); const handleEvent = (str) => { console.log(`================ ${str}`); console.log("handleEvent fired! An event has happened!"); console.log("end of event") } emitter.on('load event', () => handleEvent("load")); emitter.on('hello event', () => handleEvent("hello")); emitter.emit('load event'); emitter.emit('hello event') 复制代码
在此代码示例中,我们将导入事件模块。接下来,我们创建一个新的EventEmitter
并将其分配给变量发射器。在这个特定的例子中,我们创建了一个handleEvent
函数,它将作为一个回调函数,它将 console.log 一些东西。
该类EventEmitter
有几个我们可以使用的方法。发出事件时运行的一种方法是函数EventEmitter.on()
。
当发出事件时,将触发此特定方法。传递给函数的第一个参数是事件的名称,第二个参数是告诉我们如何处理事件的回调函数。
在此特定示例中,发出了两个事件。当我们运行上面的代码时,我们应该得到:
================ load handleEvent fired! An event has happened! end of event ================ hello handleEvent fired! An event has happened! end of event true 复制代码
emit 方法触发 on 方法,然后调用handleEvent
回调函数。
全局变量
全局对象在每个模块中都可用,因此无需导入特定模块即可使用它们。类Buffer
,例如 class 在 Node.js 中被定义为一个全局的。其他一些常见的全局对象是:
- 该
console
对象用于打印到stdout
和stderr
。 - 定时器,例如
setImmediate
、setInterval
和setTimeout
,也是全局变量。 - 该
process
对象也是全局的。
在浏览器中,顶级范围是全局范围。但是在 Node.js 中,顶级作用域不是全局作用域。
在 Node.js 中,全局对象可用于查看全局范围内可用的内容。查看下面的代码以查看示例。
console.log(global) 复制代码
//output: Object [global] { global: [Circular], process: process { title: 'node', version: 'v10.17.0', versions: { http_parser: '2.8.0', node: '10.17.0', v8: '6.8.275.32-node.54', uv: '1.28.0', zlib: '1.2.11', brotli: '1.0.7', ares: '1.15.0', modules: '64', nghttp2: '1.39.2', napi: '5', openssl: '1.1.1d', icu: '64.2', unicode: '12.1', cldr: '35.1', tz: '2019a' }, arch: 'x64', platform: 'linux', release: { name: 'node', lts: 'Dubnium', sourceUrl: 'https://nodejs.org/download/release/v10.17.0/node-v10.17.0.tar.gz', headersUrl: 'https://nodejs.org/download/release/v10.17.0/node-v10.17.0-headers.tar.gz' }, argv: [ '/usr/local/bin/node', '/usercode/index.js' ], execArgv: [], env: { HOSTNAME: '52b6928cb0cb', HOME: '/root', OLDPWD: '/', PATH: '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', LANG: 'C.UTF-8', NODE_PATH: '/usr/local/lib/node_modules/', PWD: '/usercode' }, pid: 9, features: { debug: false, uv: true, ipv6: true, tls_alpn: true, tls_sni: true, tls_ocsp: true, tls: true }, ppid: 8, execPath: '/usr/local/bin/node', debugPort: 9229, _debugProcess: [Function: _debugProcess], _debugEnd: [Function: _debugEnd], _startProfilerIdleNotifier: [Function: _startProfilerIdleNotifier], _stopProfilerIdleNotifier: [Function: _stopProfilerIdleNotifier], abort: [Function: abort], chdir: [Function: chdir], umask: [Function: umask], _getActiveRequests: [Function: _getActiveRequests], _getActiveHandles: [Function: _getActiveHandles], _kill: [Function: _kill], cwd: [Function: cwd], dlopen: [Function: dlopen], reallyExit: [Function: reallyExit], uptime: [Function: uptime], getuid: [Function: getuid], geteuid: [Function: geteuid], getgid: [Function: getgid], getegid: [Function: getegid], getgroups: [Function: getgroups], _rawDebug: [Function], moduleLoadList: [ 'Internal Binding module_wrap', 'Binding contextify', 'Internal Binding worker', 'NativeModule events', 'NativeModule internal/async_hooks', 'NativeModule internal/errors', 'Binding uv', 'Binding buffer', 'Binding async_wrap', 'Internal Binding async_wrap', 'Binding config', 'Binding icu', 'NativeModule util', 'NativeModule internal/util/inspect', 'Binding util', 'NativeModule internal/util', 'Binding constants', 'Internal Binding types', 'NativeModule internal/util/types', 'NativeModule internal/validators', 'NativeModule internal/encoding', 'Internal Binding icu', 'NativeModule buffer', 'NativeModule internal/buffer', 'NativeModule internal/process/per_thread', 'NativeModule internal/process/main_thread_only', 'NativeModule internal/process/stdio', 'NativeModule assert', 'NativeModule internal/assert', 'NativeModule fs', 'NativeModule path', 'NativeModule internal/constants', 'Binding fs', 'NativeModule internal/fs/streams', 'NativeModule internal/fs/utils', 'NativeModule stream', 'NativeModule internal/streams/pipeline', 'NativeModule internal/streams/end-of-stream', 'NativeModule internal/streams/legacy', 'NativeModule _stream_readable', 'NativeModule internal/streams/buffer_list', 'NativeModule internal/streams/destroy', 'NativeModule internal/streams/state', 'NativeModule _stream_writable', 'NativeModule _stream_duplex', 'NativeModule _stream_transform', 'NativeModule _stream_passthrough', 'NativeModule internal/url', 'NativeModule internal/querystring', 'Binding url', 'NativeModule internal/process/warning', 'NativeModule internal/process/next_tick', 'NativeModule internal/process/promises', 'Internal Binding util', 'NativeModule internal/fixed_queue', 'Binding performance', 'Binding trace_events', 'NativeModule internal/inspector_async_hook', 'Binding inspector', 'NativeModule internal/options', 'Internal Binding options', 'NativeModule timers', 'Binding timer_wrap', 'NativeModule internal/linkedlist', 'NativeModule internal/timers', 'NativeModule console', 'Binding tty_wrap', 'Internal Binding tty_wrap', 'NativeModule internal/fs/sync_write_stream', 'NativeModule internal/modules/cjs/loader', 'NativeModule vm', 'NativeModule internal/modules/cjs/helpers', 'NativeModule url', 'NativeModule internal/safe_globals', 'Internal Binding contextify' ], binding: [Function: binding], _linkedBinding: [Function: _linkedBinding], _events: [Object: null prototype] { newListener: [Function], removeListener: [Function], warning: [Function] }, _eventsCount: 3, _maxListeners: undefined, _fatalException: [Function], domain: null, _exiting: false, assert: [Function: deprecated], config: { target_defaults: [Object], variables: [Object] }, setUncaughtExceptionCaptureCallback: [Function], hasUncaughtExceptionCaptureCallback: [Function], emitWarning: [Function], nextTick: [Function: nextTick], _tickCallback: [Function: _tickCallback], stdout: [Getter], stderr: [Getter], stdin: [Getter], openStdin: [Function], initgroups: [Function: initgroups], setegid: [Function: setegid], seteuid: [Function: seteuid], setgid: [Function: setgid], setuid: [Function: setuid], setgroups: [Function: setgroups], hrtime: { [Function: hrtime] bigint: [Function] }, cpuUsage: [Function: cpuUsage], memoryUsage: [Function: memoryUsage], exit: [Function], kill: [Function], argv0: 'node', allowedNodeEnvironmentFlags: [Getter/Setter], mainModule: Module { id: '.', exports: {}, parent: null, filename: '/usercode/index.js', loaded: false, children: [], paths: [Array] } }, Buffer: { [Function: Buffer] poolSize: 8192, from: [Function: from], of: [Function: of], alloc: [Function: alloc], allocUnsafe: [Function: allocUnsafe], allocUnsafeSlow: [Function: allocUnsafeSlow], isBuffer: [Function: isBuffer], compare: [Function: compare], isEncoding: [Function: isEncoding], concat: [Function: concat], byteLength: [Function: byteLength], [Symbol(kIsEncodingSymbol)]: [Function: isEncoding] }, clearImmediate: [Function: clearImmediate], clearInterval: [Function: clearInterval], clearTimeout: [Function: clearTimeout], setImmediate: { [Function: setImmediate] [Symbol(util.promisify.custom)]: [Function] }, setInterval: [Function: setInterval], setTimeout: { [Function: setTimeout] [Symbol(util.promisify.custom)]: [Function] } } 复制代码
如何构建一个基本的 Node.js 项目
让我们通过创建一个简单的 Node.js 文件来学习如何开始使用 Node.js。在这个例子中,我们将设置我们的计算机作为服务器工作!
安装 Node.js 和 NPM
首先,您需要转到站点Node.js 站点并下载文件。
按照安装提示重新启动机器以获得最佳效果。
另一种安装 Node.js 的方法是使用包管理器。
然后,通过使用以下命令打印版本来测试它是否正常工作:
> node -v 复制代码
您还应该通过使用以下命令打印版本来测试 npm:
> npm -v 复制代码
创建一个文件
正确安装 Node.js 后,创建一个 Node.js 文件。在此示例中,我们将其命名为“first.js”。然后我们添加以下代码并将文件保存在您的计算机上,如下所示:C:\Users\Your Name\first.js
var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/html'}); res.end('Hello World!'); }).listen(8080); 复制代码
这段代码本质上是告诉计算机打印“Hello World!” 在端口 8080 上访问时。
命令行界面
Node.js 文件必须在您计算机的“命令行界面”程序中启动。导航到包含文件“first.js”的文件夹。
C:\Users\Your Name>_ 复制代码
启动你的文件
然后需要由 Node.js 启动此文件。通过启动命令行界面、编写node first.js
并单击 enter 来执行此操作:
C:\Users\Your Name>node myfirst.js 复制代码
惊人的!现在您的计算机已设置为服务器,因此当您访问计算机的 8080 端口时,“Hello World!” 将打印消息。
要实时查看,请打开浏览器并输入:http://localhost:8080