译文出处

自己在阅读 NodeJS 文书档案中读出的贰十一个套路

2016/11/21 · JavaScript
· NodeJS

原来的文章出处: David
Gilbertson   译文出处:王下邀月熊_Chevalier   

就算自身早已用了七年多的NodeJS,也早已感到本身对其无所不知。不过笔者临近未有有安静的坐下来留神地读书NodeJS的完整文书档案。假使有熟稔本人的心上人应该知道,作者事先已经看了HTML,DOM,Web
APIs,CSS,SVG以及ECMAScript的文书档案,NodeJS是自笔者那几个类别的终极叁个待翻阅的群山。在阅读文书档案的进度中本身也开采了众多当然不晓得的学问,笔者认为自家有必不可缺分享给我们。不过文书档案更加多的是平铺直叙,由此作者也以涉猎的相继列举出笔者以为须要领会的点。

querystring:能够当作通用分析器的模块

众多时候我们会从数据库或另外地点获得这种奇异格式的字符串:name:Sophie;shape:fox;condition:new,一般的话大家会动用字符串切割的秘籍来说字符串划分到JavaScript
Object。可是querystring也是个不利的现有的工具:

JavaScript

const weirdoString = `name:Sophie;shape:fox;condition:new`; const
result = querystring.parse(weirdoString, `;`, `:`); // result: // {
// name: `Sophie`, // shape: `fox`, // condition: `new`, // };

1
2
3
4
5
6
7
8
const weirdoString = `name:Sophie;shape:fox;condition:new`;
const result = querystring.parse(weirdoString, `;`, `:`);
// result:
// {
//   name: `Sophie`,
//   shape: `fox`,
//   condition: `new`,
// };

V8 Inspector

--inspect参数运转你的Node应用程序,它会上报你某些U福睿斯L。将该U奥迪Q7L复制到Chrome中并展开,你就足以应用Chrome
DevTools来调度你的Node应用程序啦。详细的尝试能够参照那篇小说。不过要求潜心的是,该参数仍旧属于实验性质。
图片 1

nextTick 与 setImmediate的区别

这两货的界别大概光从名字上还看不出来,笔者感觉应该给它们取个外号:

  • process.nextTick()应该为process.sendThisToTheStartOfTheQueue()
  • setImmediate应该为sendThisToTheEndOfTheQueue()

再说句不相干的,React中的Props应为stuffThatShouldStayTheSameIfTheUserRefreshes,而State应该为stuffThatShouldBeForgottenIfTheUserRefreshes

Server.listen 能够应用Object作为参数

自家更欣赏命名参数的法子调用函数,那样相较于仅依照顺序的无命名参数法会越来越直观。别忘了Server.listen也能够选拔有个别Object作为参数:

JavaScript

require(`http`) .createServer() .listen({ port: 8080, host:
`localhost`, }) .on(`request`, (req, res) => { res.end(`Hello
World!`); });

1
2
3
4
5
6
7
8
9
require(`http`)
  .createServer()
  .listen({
    port: 8080,
    host: `localhost`,
  })
  .on(`request`, (req, res) => {
    res.end(`Hello World!`);
  });

可是这一个特点不是发挥在http.Server其一API中,而是在其父级net.Server的文书档案中。

相对地址

你传入fs模块的偏离能够是对立地址,即相对于process.cwd()。测度有些人一度明白了,可是小编前边平素以为是不得不利用相对化地址:

JavaScript

const fs = require(`fs`); const path = require(`path`); // why have
I always done this… fs.readFile(path.join(__dirname,
`myFile.txt`), (err, data) => { // do something }); // when I could
just do this? fs.readFile(`./path/to/myFile.txt`, (err, data) => {
// do something });

1
2
3
4
5
6
7
8
9
10
const fs = require(`fs`);
const path = require(`path`);
// why have I always done this…
fs.readFile(path.join(__dirname, `myFile.txt`), (err, data) => {
  // do something
});
// when I could just do this?
fs.readFile(`./path/to/myFile.txt`, (err, data) => {
  // do something
});

Path Parsing:路线分析

事先作者平素不知情的某部意义正是从某些文件名中分析出路径,文件名,文件扩充等等:

JavaScript

myFilePath = `/someDir/someFile.json`; path.parse(myFilePath).base ===
`someFile.json`; // true path.parse(myFilePath).name === `someFile`;
// true path.parse(myFilePath).ext === `.json`; // true

1
2
3
4
myFilePath = `/someDir/someFile.json`;
path.parse(myFilePath).base === `someFile.json`; // true
path.parse(myFilePath).name === `someFile`; // true
path.parse(myFilePath).ext === `.json`; // true

Logging with colors

别忘了console.dir(obj,{colors:true})能够以分歧的情调打字与印刷出键与值,那点会大大扩大日志的可读性。

动用setInterval实施定期职分

本人喜欢使用setInterval来定期推行数据库清理职责,可是暗许景况下在设有setInterval的时候NodeJS并不会脱离,你能够采纳如下的格局让Node沉睡:

JavaScript

const dailyCleanup = setInterval(() => { cleanup(); }, 1000 * 60 *
60 * 24); dailyCleanup.unref();

1
2
3
4
const dailyCleanup = setInterval(() => {
  cleanup();
}, 1000 * 60 * 60 * 24);
dailyCleanup.unref();

Use Signal Constants

若是你品味在NodeJS中杀死有些进度,预计您用过如下语法:

JavaScript

process.kill(process.pid, `SIGTERM`);

1
process.kill(process.pid, `SIGTERM`);

以此没啥难题,不过既然第一个参数同期能够使用字符串与整形变量,那么还不比接纳全局变量呢:

JavaScript

process.kill(process.pid, os.constants.signals.SIGTERM);

1
process.kill(process.pid, os.constants.signals.SIGTERM);

IP Address Validation

NodeJS中富含内置的IP地址校验工具,这点得防止受你写额外的正则表明式:

JavaScript

require(`net`).isIP(`10.0.0.1`) 返回 4
require(`net`).isIP(`cats`) 返回 0

1
2
require(`net`).isIP(`10.0.0.1`) 返回 4
require(`net`).isIP(`cats`) 返回 0

os.EOF

不晓得你有未有手写过行停止符,看上去可倒霉好啊。NodeJS内置了os.EOF,其在Windows下是rn,其余地方是n,使用os.EOL能够让你的代码在差异的操作系统上有限支撑一致性:

JavaScript

const fs = require(`fs`); // bad fs.readFile(`./myFile.txt`,
`utf8`, (err, data) => { data.split(`\r\n`).forEach(line =>
{ // do something }); }); // good const os = require(`os`);
fs.readFile(`./myFile.txt`, `utf8`, (err, data) => {
data.split(os.EOL).forEach(line => { // do something }); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const fs = require(`fs`);
// bad
fs.readFile(`./myFile.txt`, `utf8`, (err, data) => {
  data.split(`\r\n`).forEach(line => {
    // do something
  });
});
// good
const os = require(`os`);
fs.readFile(`./myFile.txt`, `utf8`, (err, data) => {
  data.split(os.EOL).forEach(line => {
    // do something
  });
});

HTTP 状态码

NodeJS帮我们放开了HTTP状态码及其描述,相当于http.STATUS_CODES,键为状态值,值为描述:
图片 2

   译文出处。您能够遵照如下方法应用:

JavaScript

someResponse.code === 301; // true
require(`http`).STATUS_CODES[someResponse.code] === `Moved
Permanently`; // true

1
2
someResponse.code === 301; // true
require(`http`).STATUS_CODES[someResponse.code] === `Moved Permanently`; // true

幸免十分崩溃

不常境遇如下这种导致服务端崩溃的事态还是挺无可奈何的:

JavaScript

const jsonData = getDataFromSomeApi(); // But oh no, bad data! const
data = JSON.parse(jsonData); // Loud crashing noise.

1
2
const jsonData = getDataFromSomeApi(); // But oh no, bad data!
const data = JSON.parse(jsonData); // Loud crashing noise.

本身为了制止这种情形,在全局加上了叁个:

JavaScript

process.on(`uncaughtException`, console.error);

1
process.on(`uncaughtException`, console.error);

本来,这种艺术绝不是顶级实行,尽管是在大型项目中自己依然会选取PM2,然后将具备只怕崩溃的代码插足到try...catch中。

Just this once()

除了on方法,once方法也适用于全部的EventEmitters,希望笔者不是最后才清楚这些的:

JavaScript

server.once(`request`, (req, res) => res.end(`No more from
me.`));

1
server.once(`request`, (req, res) => res.end(`No more from me.`));

Custom Console

你可以使用new console.Console(standardOut,errorOut),然后设置自定义的输出流。你可以接纳创设console将数据输出到文件或许Socket可能第三方中。

DNS lookup

有些年轻人告诉本身,Node   译文出处。并不会缓存DNS查询新闻,由此你在行使U科雷傲L之后要等个几飞秒才干博取到数量。不超过实际在您能够选拔dns.lookup()来缓存数据:

JavaScript

dns.lookup(`www.myApi.com`, 4, (err, address) => {
cacheThisForLater(address); });

1
2
3
dns.lookup(`www.myApi.com`, 4, (err, address) => {
  cacheThisForLater(address);
});

fs 在分歧OS上有一定距离

  • fs.stats()回来的目的中的mode个性在Windows与任何操作系统中留存差距。
  • fs.lchmod()仅在macOS中有效。
  • 仅在Windows中扶助调用fs.symlink()时使用type参数。
  • 仅仅在macOS与Windows中调用fs.watch()时传入recursive   译文出处。选项。
  • 在Linux与Windows中fs.watch()的回调能够流传有个别文件名
  • 使用fs.open()以及a+质量展开有个别目录时只是在FreeBSD以及Windows上起作用,在macOS以及Linux上则存在难题。
  • 在Linux下以扩展情势张开有个别文件时,传入到fs.write()position参数会被忽视。

net 模块大概比http快上两倍

作者在文书档案中看看部分关于双方质量的商议,还特意运营了多少个服务器来进展实际相比。结果来看http.Server大意每秒能够连接3400个诉求,而net.Server能够接入差非常少5500个央浼。

JavaScript

// This makes two connections, one to a tcp server, one to an http
server (both in server.js) // It fires off a bunch of connections and
times the response // Both send strings. const net = require(`net`);
const http = require(`http`); function parseIncomingMessage(res) {
return new Promise((resolve) => { let data = “; res.on(`data`,
(chunk) => { data += chunk; }); res.on(`end`, () =>
resolve(data)); }); } const testLimit = 5000; /* —————— */
/* — NET client — */ /* —————— */ function
testNetClient() { const netTest = { startTime: process.hrtime(),
responseCount: 0, testCount: 0, payloadData: { type: `millipede`,
feet: 100, test: 0, }, }; function handleSocketConnect() {
netTest.payloadData.test++; netTest.payloadData.feet++; const payload =
JSON.stringify(netTest.payloadData); this.end(payload, `utf8`); }
function handleSocketData() { netTest.responseCount++; if
(netTest.responseCount === testLimit) { const hrDiff =
process.hrtime(netTest.startTime); const elapsedTime = hrDiff[0] *
1e3 + hrDiff[1] / 1e6; const requestsPerSecond = (testLimit /
(elapsedTime / 1000)).toLocaleString(); console.info(`net.Server
handled an average of ${requestsPerSecond} requests per second.`); } }
while (netTest.testCount < testLimit) { netTest.testCount++; const
socket = net.connect(8888, handleSocketConnect); socket.on(`data`,
handleSocketData); } } /* ——————- */ /* — HTTP client —
*/ /* ——————- */ function testHttpClient() { const
httpTest = { startTime: process.hrtime(), responseCount: 0, testCount:
0, }; const payloadData = { type: `centipede`, feet: 100, test: 0, };
const options = { hostname: `localhost`, port: 8080, method: `POST`,
headers: { ‘Content-Type’: `application/x-www-form-urlencoded`, }, };
function handleResponse(res) { parseIncomingMessage(res).then(() => {
httpTest.responseCount++; if (httpTest.responseCount === testLimit) {
const hrDiff = process.hrtime(httpTest.startTime); const elapsedTime =
hrDiff[0] * 1e3 + hrDiff[1] / 1e6; const requestsPerSecond =
(testLimit / (elapsedTime / 1000)).toLocaleString();
console.info(`http.Server handled an average of ${requestsPerSecond}
requests per second.`); } }); } while (httpTest.testCount <
testLimit) { httpTest.testCount++; payloadData.test =
httpTest.testCount; payloadData.feet++; const payload =
JSON.stringify(payloadData); options[`Content-Length`] =
Buffer.byteLength(payload); const req = http.request(options,
handleResponse); req.end(payload); } } /* — Start tests — */ // flip
these occasionally to ensure there’s no bias based on order
setTimeout(() => { console.info(`Starting testNetClient()`);
testNetClient(); }, 50); setTimeout(() => { console.info(`Starting
testHttpClient()`); testHttpClient(); }, 2000);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// This makes two connections, one to a tcp server, one to an http server (both in server.js)
// It fires off a bunch of connections and times the response
 
// Both send strings.
 
const net = require(`net`);
const http = require(`http`);
 
function parseIncomingMessage(res) {
  return new Promise((resolve) => {
    let data = “;
 
    res.on(`data`, (chunk) => {
      data += chunk;
    });
 
    res.on(`end`, () => resolve(data));
  });
}
 
const testLimit = 5000;
 
 
/*  ——————  */
/*  —  NET client  —  */
/*  ——————  */
function testNetClient() {
  const netTest = {
    startTime: process.hrtime(),
    responseCount: 0,
    testCount: 0,
    payloadData: {
      type: `millipede`,
      feet: 100,
      test: 0,
    },
  };
 
  function handleSocketConnect() {
    netTest.payloadData.test++;
    netTest.payloadData.feet++;
 
    const payload = JSON.stringify(netTest.payloadData);
 
    this.end(payload, `utf8`);
  }
 
  function handleSocketData() {
    netTest.responseCount++;
 
    if (netTest.responseCount === testLimit) {
      const hrDiff = process.hrtime(netTest.startTime);
      const elapsedTime = hrDiff[0] * 1e3 + hrDiff[1] / 1e6;
      const requestsPerSecond = (testLimit / (elapsedTime / 1000)).toLocaleString();
 
      console.info(`net.Server handled an average of ${requestsPerSecond} requests per second.`);
    }
  }
 
  while (netTest.testCount < testLimit) {
    netTest.testCount++;
    const socket = net.connect(8888, handleSocketConnect);
    socket.on(`data`, handleSocketData);
  }
}
 
 
/*  ——————-  */
/*  —  HTTP client  —  */
/*  ——————-  */
function testHttpClient() {
  const httpTest = {
    startTime: process.hrtime(),
    responseCount: 0,
    testCount: 0,
  };
 
  const payloadData = {
    type: `centipede`,
    feet: 100,
    test: 0,
  };
 
  const options = {
    hostname: `localhost`,
    port: 8080,
    method: `POST`,
    headers: {
      ‘Content-Type’: `application/x-www-form-urlencoded`,
    },
  };
 
  function handleResponse(res) {
    parseIncomingMessage(res).then(() => {
      httpTest.responseCount++;
 
      if (httpTest.responseCount === testLimit) {
        const hrDiff = process.hrtime(httpTest.startTime);
        const elapsedTime = hrDiff[0] * 1e3 + hrDiff[1] / 1e6;
        const requestsPerSecond = (testLimit / (elapsedTime / 1000)).toLocaleString();
 
        console.info(`http.Server handled an average of ${requestsPerSecond} requests per second.`);
      }
    });
  }
 
  while (httpTest.testCount < testLimit) {
    httpTest.testCount++;
    payloadData.test = httpTest.testCount;
    payloadData.feet++;
 
    const payload = JSON.stringify(payloadData);
 
    options[`Content-Length`] = Buffer.byteLength(payload);
 
    const req = http.request(options, handleResponse);
    req.end(payload);
  }
}
 
/*  —  Start tests  —  */
// flip these occasionally to ensure there’s no bias based on order
setTimeout(() => {
  console.info(`Starting testNetClient()`);
  testNetClient();
}, 50);
 
setTimeout(() => {
  console.info(`Starting testHttpClient()`);
  testHttpClient();
}, 2000);

JavaScript

// This sets up two servers. A TCP and an HTTP one. // For each
response, it parses the received string as JSON, converts that object
and returns a string const net = require(`net`); const http =
require(`http`); function renderAnimalString(jsonString) { const data
= JSON.parse(jsonString); return `${data.test}: your are a ${data.type}
and you have ${data.feet} feet.`; } /* —————— */ /* —
NET server — */ /* —————— */ net .createServer((socket)
=> { socket.on(`data`, (jsonString) => {
socket.end(renderAnimalString(jsonString)); }); }) .listen(8888); /*
——————- */ /* — HTTP server — */ /*
——————- */ function parseIncomingMessage(res) { return new
Promise((resolve) => { let data = “; res.on(`data`, (chunk)
=> { data += chunk; }); res.on(`end`, () => resolve(data)); });
} http .createServer() .listen(8080) .on(`request`, (req, res) => {
parseIncomingMessage(req).then((jsonString) => {
res.end(renderAnimalString(jsonString)); }); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// This sets up two servers. A TCP and an HTTP one.
// For each response, it parses the received string as JSON, converts that object and returns a string
const net = require(`net`);
const http = require(`http`);
 
function renderAnimalString(jsonString) {
  const data = JSON.parse(jsonString);
  return `${data.test}: your are a ${data.type} and you have ${data.feet} feet.`;
}
 
 
/*  ——————  */
/*  —  NET server  —  */
/*  ——————  */
 
net
  .createServer((socket) => {
    socket.on(`data`, (jsonString) => {
      socket.end(renderAnimalString(jsonString));
    });
  })
  .listen(8888);
 
 
/*  ——————-  */
/*  —  HTTP server  —  */
/*  ——————-  */
 
function parseIncomingMessage(res) {
  return new Promise((resolve) => {
    let data = “;
 
    res.on(`data`, (chunk) => {
      data += chunk;
    });
 
    res.on(`end`, () => resolve(data));
  });
}
 
http
  .createServer()
  .listen(8080)
  .on(`request`, (req, res) => {
    parseIncomingMessage(req).then((jsonString) => {
      res.end(renderAnimalString(jsonString));
    });
  });

REPL tricks

  • 只要你是在REPL情势下,正是一贯输入node然后跻身相互状态的形式。你能够直接输入.load someFile.js下一场能够载入蕴涵自定义常量的文件。
  • 能够透过安装NODE_REPL_HISTORY=""来制止将日志写入到文件中。
  • _用来记录最终七个计算值。
  • 在REPL运转之后,全部的模块都早就直接加载成功。能够采用os.arch()而不是require(os).arch()来使用。

    1 赞 3 收藏
    评论

图片 3

发表评论

电子邮件地址不会被公开。 必填项已用*标注