简介
javascript尽管始终都能够做服务端编程语言,然而它更多的是以客户端编程语言来展现在世人背后的。兴许javascript本人都遗记了还能够做服务器端编程,直到2009年nodejs的横空出世。
nodejs的历史
javascript作为一门解释性语言,是不须要像C或者C++那样进行编译的。然而在晚期的时候,javascript引擎的执行效率是比拟低的,所以导致javascript只能做做dom操作。
随着ajax的衰亡和古代web2.0的技术的倒退,支流浏览器开发商尽可能的晋升javascript的执行效率,最初Chrome V8呈现了,Chrome V8是 Chromium 我的项目开源的 JavaScript 引擎,使得javascript的执行效率失去了极大的晋升。
nodejs借着V8浴火重生了。
nodejs从一诞生就取得了极大的关注。比拟javascript的开发者还是十分十分多的。而且一门语言能够通用前后端是如许的有吸引力。
nodejs从2009年倒退到2020年的nodejs 14,经验了11年的历史,和它的先辈javascript相比还是很年老,然而因为其开放性和包容性,nodejs在以一个十分快的速度向前倒退。
nodejs简介
nodejs借助于V8引擎和一组异步的 I/O 原生性能,极大的晋升了nodejs的解决效率。
异步IO咱们大家应该都很分明,和同步IO相比,线程不必阻塞,能够去解决其余更有意义的事件。只是在响应返回的时候复原操作,所以不会节约CPU工夫。
咱们简略看一下nodejs的IO模型:
一个好的语言须要有良好的生态系统相配合,因为语言自身只能提供最根本的一些操作,咱们还须要第三方零碎来丰盛这个语言的生态。
而nodejs的npm仓库,托管着寰球最大的开源库生态系统。
基本上应用nodejs你能够实现绝大多数须要的性能。
nodejs的另外一个特点就是简略,考虑一下咱们最罕用的web利用,如果用java来写,十分麻烦,你还须要一个web服务器。
在nodejs中,一切都是那么的简略:
const http = require('http')const hostname = '127.0.0.1'const port = 3000const server = http.createServer((req, res) => { res.statusCode = 200 res.setHeader('Content-Type', 'text/plain') res.end('welcome to www.flydean.com\n')})server.listen(port, hostname, () => { console.log(`please visit http://${hostname}:${port}/`)})
下面的代码就创立了一个web服务,监听在3000端口,
咱们首先引入了http模块,用来进行http解决。
接着应用http 的 createServer() 办法会创立新的 HTTP 服务器并返回它。
在createServer办法外部,咱们能够设定要返回的对象。
最初启用server.listen性能,来监听特定的端口和服务器,当服务就绪之后,会调用前面的回调函数,执行特定的命令。
每当接管到新的申请的时候,就会触发request事件,request事件能够传递两个参数:
- request 是一个http.IncomingMessage对象,提供了申请的详细信息。
- response 是一个http.ServerResponse对象,用于返回数据给调用方。
在下面的例子中,咱们并没有应用request,而是应用response间接构建了返回的对象。
咱们设置了statusCode和header,最初应用end来敞开响应。
这就是一个简略应用的nodejs程序。
nodejs的运行环境
nodejs作为js的一种,是一种解释性语言,个别解释性语言都有两种运行形式。
一种是间接运行,一种是开启一个解释性的环境,在其中运行,nodejs也不例外。
间接运行很简略,咱们写好nodejs的程序之后,比方app.js,间接这样运行:
node app.js
如果间接执行node命令,就会开启REPL模式:
nodeWelcome to Node.js v12.13.1.Type ".help" for more information.>
REPL 也被称为运行评估打印循环,是一种编程语言环境(次要是控制台窗口),它应用单个表达式作为用户输出,并在执行后将后果返回到控制台。
REPL有什么作用呢?
第一,咱们能够间接在REPL中运行某些测试方法,已验证输入后果。
比方这样:
> console.log('www.flydean.com');www.flydean.com
除此之外REPL还有一些更加有用的性能,咱们晓得JS中所有皆对象,比方下面咱们提到的http对象,如果咱们想晓得http对象的大略构造怎么办呢?
间接在REPL环境中输出http即可:
> http{ _connectionListener: [Function: connectionListener], METHODS: [ 'ACL', 'BIND', 'CHECKOUT', 'CONNECT', 'COPY', 'DELETE', 'GET', 'HEAD', 'LINK', 'LOCK', 'M-SEARCH', 'MERGE', 'MKACTIVITY', 'MKCALENDAR', 'MKCOL', 'MOVE', 'NOTIFY', 'OPTIONS', 'PATCH', 'POST', 'PROPFIND', 'PROPPATCH', 'PURGE', 'PUT', 'REBIND', 'REPORT', 'SEARCH', 'SOURCE', 'SUBSCRIBE', 'TRACE', 'UNBIND', 'UNLINK', 'UNLOCK', 'UNSUBSCRIBE' ], STATUS_CODES: { '100': 'Continue', '101': 'Switching Protocols', '102': 'Processing', '103': 'Early Hints', '200': 'OK', '201': 'Created', '202': 'Accepted', '203': 'Non-Authoritative Information', '204': 'No Content', '205': 'Reset Content', '206': 'Partial Content', '207': 'Multi-Status', '208': 'Already Reported', '226': 'IM Used', '300': 'Multiple Choices', '301': 'Moved Permanently', '302': 'Found', '303': 'See Other', '304': 'Not Modified', '305': 'Use Proxy', '307': 'Temporary Redirect', '308': 'Permanent Redirect', '400': 'Bad Request', '401': 'Unauthorized', '402': 'Payment Required', '403': 'Forbidden', '404': 'Not Found', '405': 'Method Not Allowed', '406': 'Not Acceptable', '407': 'Proxy Authentication Required', '408': 'Request Timeout', '409': 'Conflict', '410': 'Gone', '411': 'Length Required', '412': 'Precondition Failed', '413': 'Payload Too Large', '414': 'URI Too Long', '415': 'Unsupported Media Type', '416': 'Range Not Satisfiable', '417': 'Expectation Failed', '418': "I'm a Teapot", '421': 'Misdirected Request', '422': 'Unprocessable Entity', '423': 'Locked', '424': 'Failed Dependency', '425': 'Unordered Collection', '426': 'Upgrade Required', '428': 'Precondition Required', '429': 'Too Many Requests', '431': 'Request Header Fields Too Large', '451': 'Unavailable For Legal Reasons', '500': 'Internal Server Error', '501': 'Not Implemented', '502': 'Bad Gateway', '503': 'Service Unavailable', '504': 'Gateway Timeout', '505': 'HTTP Version Not Supported', '506': 'Variant Also Negotiates', '507': 'Insufficient Storage', '508': 'Loop Detected', '509': 'Bandwidth Limit Exceeded', '510': 'Not Extended', '511': 'Network Authentication Required' }, Agent: [Function: Agent] { defaultMaxSockets: Infinity }, ClientRequest: [Function: ClientRequest], IncomingMessage: [Function: IncomingMessage], OutgoingMessage: [Function: OutgoingMessage], Server: [Function: Server], ServerResponse: [Function: ServerResponse], createServer: [Function: createServer], get: [Function: get], request: [Function: request], maxHeaderSize: [Getter], globalAgent: [Getter/Setter]}
间接输入了http对象的简洁构造,咱们还能够应用tab按钮来主动补全http的办法:
> http.http.__defineGetter__ http.__defineSetter__ http.__lookupGetter__ http.__lookupSetter__ http.__proto__ http.constructorhttp.hasOwnProperty http.isPrototypeOf http.propertyIsEnumerable http.toLocaleString http.toString http.valueOfhttp.Agent http.ClientRequest http.IncomingMessage http.METHODS http.OutgoingMessage http.STATUS_CODEShttp.Server http.ServerResponse http._connectionListener http.createServer http.get http.globalAgenthttp.maxHeaderSize http.request
PREL还反对一些特定的点操作:
> .help.break Sometimes you get stuck, this gets you out.clear Alias for .break.editor Enter editor mode.exit Exit the repl.help Print this help message.load Load JS from a file into the REPL session.save Save all evaluated commands in this REPL session to a file
PERL还有一个非凡变量 _ ,如果在某些代码之后输出 _,则会打印最初一次操作的后果。
process
process 对象是一个全局变量,提供了无关以后 Node.js 过程的信息并对其进行管制。 作为全局变量,它始终可供 Node.js 应用程序应用,无需应用 require()。 它也能够应用 require() 显式地拜访。
因为process代表的是nodejs的过程信息,所以能够解决过程终止,读取环境变量,接管命令行参数等作用。
终止过程
先看一下怎么应用process来终止过程:
process.exit(0)
0示意失常退出,当然,咱们能够传入不同的退出码,示意不同的含意。
失常状况下,如果没有异步操作正在期待,那么 Node.js 会以状态码 0 退出,其余状况下,会用如下的状态码:
1 未捕捉异样 - 一个未被捕捉的异样, 并且没被 domain 或 'uncaughtException' 事件处理器解决。
2 - 未被应用 (Bash 为防外部滥用而保留)
3 外部的 JavaScript 解析谬误 - Node.js 外部的 JavaScript 源代码在疏导过程中导致了一个语法解析谬误。个别只会在开发 Node.js 自身的时候呈现。
4 外部的 JavaScript 执行失败 - 疏导过程执行 Node.js 外部的 JavaScript 源代码时,返回函数值失败。个别只会在开发 Node.js 自身的时候呈现。
5 致命谬误 - 在 V8 中有一个致命的谬误。 比拟典型的是以 FATALERROR 为前缀从 stderr 打印进去的音讯。
6 非函数的外部异样解决 - 产生了一个外部异样,然而外部异样处理函数被设置成了一个非函数,或者不能被调用。
7 外部异样解决运行时失败 - 有一个不能被捕捉的异样,在试图解决这个异样时,处理函数自身抛出了一个谬误。比方, 如果一个 'uncaughtException' 或者 domain.on('error') 处理函数抛出了一个谬误。
8 - 未被应用,在之前版本的 Node.js, 退出码 8 有时候示意一个未被捕捉的异样。
9 - 不可用参数 - 某个未知选项没有确定,或者没给必须要的选项填值。
10 外部的 JavaScript 运行时失败 - 调用疏导函数时,疏导过程执行 Node.js 外部的 JavaScript 源代码抛出谬误。 个别只会在开发 Node.js 自身的时候呈现。
12 不可用的调试参数
13 未实现的Top-Level Await: await传入的Promise始终没有调用resolve办法
128 退出信号 - 如果 Node.js 接管到致命信号, 诸如 SIGKILL 或 SIGHUP,那么它的退出代码将是 128 加上信号的码值。 例如,信号 SIGABRT 的值为 6,因而预期的退出代码将为 128 + 6 或 134。
咱们能够通过process的on办法,来监听信号事件:
process.on('SIGTERM', () => { server.close(() => { console.log('过程已终止') })})
什么是信号?信号是一个 POSIX 外部通信零碎:发送告诉给过程,以告知其产生的事件。
或者咱们能够从程序外部发送这个信号:
process.kill(process.pid, 'SIGTERM')
env
因为process过程是和外部环境打交道的,process提供了env属性,该属性承载了在启动过程时设置的所有环境变量。
默认状况下,env中的NODE_ENV被设置为development。
process.env.NODE_ENV // "development"
咱们能够通过批改这个环境变量,来切换nodejs的不同运行环境。
argv
process提供了argv来接管内部参数。
比方:
node app.js joe
argv是一个蕴含所有命令行调用参数的数组。
下面的例子中,第一个参数是 node 命令的残缺门路。第二个参数是正被执行的文件的残缺门路。所有其余的参数从第三个地位开始。
要想获取joe,咱们能够这样做:
const args = process.argv.slice(2)args[0]
如果是key=value的状况,咱们能够这样传参数,并且应用minimist 库来解决参数:
node app.js --name=joeconst args = require('minimist')(process.argv.slice(2))args['name'] //joe
CLI交互
从 nodejs7开始,nodejs提供了readline模块,能够从process.stdin获取输出:
const readline = require('readline').createInterface({ input: process.stdin, output: process.stdout})readline.question(`how are you?`, answer => { console.log(`${answer}!`) readline.close()})
如果须要更加简单的操作,则能够应用Inquirer.js:
const inquirer = require('inquirer')var questions = [ { type: 'input', name: 'hello', message: "how are you?" }]inquirer.prompt(questions).then(answers => { console.log(`${answers['hello']}!`)})
exports模块
nodejs领有内置的模块零碎,当咱们须要应用其余lib提供的性能时候,咱们能够应用require来引入其余lib公开的模块。
然而前提是该lib须要公开,也就是exports对应的模块进去。
nodejs的对象导出有两种形式module.exports和将对象增加为 exports 的属性。
先看第一种形式,square 模块定义在 square.js 中:
module.exports = class Square { constructor(width) { this.width = width; } area() { return this.width ** 2; }};
上面的例子中, bar.js 应用了导出 Square 类的 square 模块:
const Square = require('./square.js');const mySquare = new Square(2);console.log(`mySquare 的面积是 ${mySquare.area()}`);
再看第二种形式,定义一个circle.js:
const { PI } = Math;exports.area = (r) => PI * r ** 2;exports.circumference = (r) => 2 * PI * r;
应用:
const circle = require('./circle.js');console.log(`半径为 4 的圆的面积是 ${circle.area(4)}`);
两者都能够导出特定的模块,然而module.exports只会导出特定的对象,而exports是将对象增加为exports的属性,咱们还须要依据属性名称来查找对象的属性。
nodejs API
除了咱们下面提到的http,process, nodejs还提供了很多其余十分有用的API :
nodejs的框架
除了根本的nodejs之外,nodejs还有十分多优良的框架,借助这些框架咱们能够是nodejs程序的搭建更加容易和弱小。
像AdonisJs,express,koa,Socket.io等等。
本文作者:flydean程序那些事本文链接:http://www.flydean.com/nodejs-kickoff/
本文起源:flydean的博客
欢送关注我的公众号:「程序那些事」最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!