0. 记录
一些不属于正文的零散内容。
0.1 为什么要学习node.js
- 企业需求
- 具有服务端开发经验
- 前端(front-end)
- 后端(back-end)
- 全栈开发工程师:不分前后端,都可以做
0.2 配置问题
更新Node.js
参考资料:node升级神器-n | 简书
sudo npm install -g n
sudo n stable //更新至稳定版
sudo n latest //更新至最新版
sudo n lts //更新至最新的LTS正式版本
使用ES6标准
文档:Node.js v14.7.0 Documentation
二选一:
- 将文件名后缀更改为mjs,使用命令
node --experimental-modules myapp.mjs
- 在
package.json
文件中添加属性:"type":"module"
0.3 功能函数
sleep
function sleep(milliSeconds){
var startTime =new Date().getTime();
while(new Date().getTime() < startTime + milliSeconds);
}
exec
import { exec } from "child_process";
exec("find /home/satone/",function(error, stdout, stderr){
response.writeHead(200,{"Content-Type":"text/plain"});
response.write(stdout);
response.end();
});
1. 学习资料
1.1 主要资料
1.2 辅助资料
2. 介绍
服务端的JavaScript,使用Google的V8虚拟机(Google的Chrome浏览器使用的JavaScript执行环境)来解释和执行JavaScript代码。
2.1 模块化编程
模块化编程是Node.js的重要思想,它让JavaScript的大规模工程成为可能。
2.1.1 export导出模块接口
// a.js
export default function() {}
export function a () {}
var b = 'xxx';
export {b}; // 这是ES6的写法,实际上就是{b:b}
setTimeout(() => b = 'ooo', 1000);
export var c = 100;
export在导出模块时,必须与模块内部的变量具有一一对应的关系。export 1
没有任何意义,也不可能在import的时候有一个变量与之对应,var a = 1; export a
虽然看上去成立,但是a的值是一个数字,根本无法完成解构,因此必须写成export {a}
的形式。即使a被赋值为一个function,也是不允许的。而且,大部分风格都建议,模块中最好在末尾用一个export导出所有的接口,例如:export {fun as default,a,b,c};
2.1.2 require导入(旧)
var http = require("http")
2.1.3 import导入(新)
import导入的语法与require不同,而且必须放在文件的最开始,前面不允许有任何逻辑代码。
import $ from 'jquery';
import * as _ from '_';
import {a,b,c} from './a';
import {default as alias, a as a_a, b, c} from './a';
import后跟上花括号是基本用法,花括号里的变量与export后面的变量一一对应。
2.1.4 as关键字
与Python中as的用法类似:取别名。
当需要从不同的模块中导入名字相同的函数时,可以用as来取别名避免冲突。
2.1.5 default关键字
default是别名的语法糖
// d.js
export default function() {}
// 等效于:
function a() {};
export {a as default};
这个语法糖的好处是在import的时候可以省去花括号。例如:
import $,{each,map} from 'jquery';
import后面的第一个$
是{default as $}
的替代写法。
2.1.6 *符号
*是代表所有,只在import中使用。
import * as _ from '_';
在意义上和import _ from '_';
是不同的,虽然实际上后面的使用方法是一样的。它表示的是把'_'
模块中的所有接口挂载到_
这个对象上,所以可以用_.each
调用某个接口。
一般不建议使用*符号进行导入,除非确实要使用到被导入模块内的所有接口,否则建议用花括号进行导入,用一个导入一个。
2.1.7 require OR import ?
- require是赋值过程,可以在任何需要的时候获得导入模块的任何接口,甚至不需要变量来中转。
- import是解构过程,只需要编译导入部分的代码,具有更高的性能。而且是较新的标准,建议使用。
3 构建应用模块
import { createServer } from "http";
createServer(function(request, response){
response.writeHead(200,{"Content-Type":"text/plain"});
response.write("Hello World");
response.end();
}).listen(8888);
console.log("server start at http://127.0.0.1:8888");
3.1 基于事件驱动的回调
Question: 在我们的Node.js程序中,当一个新的请求到达8888端口的时候,我们怎么控制流程呢?
- 创建了服务器,并且传递了一个匿名函数,无论何时服务器收到一个请求,这个函数就会被调用。
- 我们不知道请求什么时候会发生,但是我们现在有了一个处理请求的地方:它就是我们传递过去的那个函数。
- 这就是“回调”。我们给某个方法传递了一个函数,这个方法在有相应事件发生的时候调用这个函数来进行“回调”。
理解:在上文示例的代码中,创建服务器并开始监听之后,还在终端打印了一句话,运行该代码文件,会发现代码并不会停在createServer().listen();
这行,而是继续往下执行了并在终端进行了打印。但监听8888端口的函数仍然是有效的,当8888端口出现请求时,服务器会回调并执行传递至createServer()
的函数。
相似的现象(Q)
setTimeout(() => {
console.log("timeout:2s");
}, 2000);
console.log("after timeout");
的输出为:
after timeout
timeout:2s
是否也属于回调?
3.2 服务器是如何处理请求的
当回调启动,匿名函数被触发时,有两个传入参数:request, response。
它们是对象(object),可以使用它们的方法来处理HTTP请求的细节并响应请求。
在该例中,收到请求时,使用response.writeHead()
函数返回一个HTTP状态200和HTTP头的内容类型(content-type),使用 response.write()
函数在HTTP相应主体中发送文本“Hello World"。
最后调用response.end()
完成相应。
在该例中没有使用到request对象。
3.3 路由
对于不同的URL请求,服务器应该有不用的反应。
我们需要的数据都会包含在request对象中,但是为了解析这些数据,需要额外的nodejs模块,分别是url和querystring模块。
url.parse(string).query
|
url.parse(string).pathname |
| |
| |
------ -------------------
http://localhost:8888/start?foo=bar&hello=world
--- -----
| |
| |
querystring(string)["foo"] |
|
querystring(string)["hello"]
使用路由的server.js文件:
import { createServer } from "http";
import { parse } from "url";
import { route } from "./router.js";
function start() {
createServer(function(request, response){
var pathname = parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
route(pathname);
response.writeHead(200,{"Content-Type":"text/plain"});
response.write("Hello World");
response.end();
}).listen(8888);
console.log("server start at http://127.0.0.1:8888");
}
export { start };
文件结构:
文件名 | 功能 | import | export |
---|---|---|---|
index | main文件 | ./server,./router,./requestHandlers | null |
server | 启动服务器 | http,url | serverStart |
routers | 路由 | null | route |
requestHandlers | 相应请求,路由分发后实际执行的函数 | null | 各函数 |
3.4 阻塞与非阻塞
参考资料:理解node.js的事件轮询
一个请求长时间的计算会阻塞后面的请求,需要进行非阻塞操作。
2020年8月4日 19:30:27 进度:“以非阻塞操作进行请求响应” 资料
3.4.1 以非阻塞操作进行请求响应
使用exec
创建子进程,并将返回响应也放在子进程中进行。
3.5 POST请求
通过给request对象添加监听的方式获取POST请求的内容
3.6 阻塞对比非阻塞一览
本小节资料来自:阻塞对比非阻塞一览 | Node.js
阻塞 是指在 Node.js 程序中,其它 JavaScript 语句的执行,必须等待一个非 JavaScript 操作完成。这是因为当 阻塞 发生时,事件循环无法继续运行 JavaScript。
在 Node.js 中,JavaScript 由于执行 CPU 密集型操作,而不是等待一个非 JavaScript 操作(例如 I/O)而表现不佳,通常不被称为 阻塞。在 Node.js 标准库中使用 libuv 的同步方法是最常用的 阻塞 操作。原生模块中也有 阻塞 方法。
在 Node.js 标准库中的所有 I/O 方法都提供异步版本,非阻塞,并且接受回调函数。某些方法也有对应的 阻塞 版本,名字以 Sync 结尾。
阻塞 = 同步
非阻塞 = 异步
以文件系统做例子,同步文件读取:
const fs = require('fs');
const data = fs.readFileSync('/file.md'); // blocks here until file is read
console.log(data);
moreWork(); // will run after console.log
异步:
const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
if (err) throw err;
console.log(data);
});
moreWork(); // will run before console.log
在同步例子中,morework()
会在data读取完后再调用;而在异步的例子中,将不会等待文件读取,直接执行morework()
,当文件读取完毕后再回调输入readFile
的匿名函数。异步方法可以提高吞吐量。
3.6.1 阻塞与非阻塞操作混用的危险
需要注意在非阻塞操作之后的代码,都可能先于非阻塞操作中的代码执行,注意考虑可能造成的影响。
可以将相关的操作都嵌套在非阻塞操作中。
重新编辑于:2020-08-06 13:16:05
0. 记录
一些不属于正文的零散内容。
0.1 为什么要学习node.js
- 企业需求
- 具有服务端开发经验
- 前端(front-end)
- 后端(back-end)
- 全栈开发工程师:不分前后端,都可以做
0.2 配置问题
更新Node.js
参考资料:node升级神器-n | 简书
sudo npm install -g n
sudo n stable //更新至稳定版
sudo n latest //更新至最新版
sudo n lts //更新至最新的LTS正式版本
使用ES6标准
文档:Node.js v14.7.0 Documentation
二选一:
- 将文件名后缀更改为mjs,使用命令
node --experimental-modules myapp.mjs
- 在
package.json
文件中添加属性:"type":"module"
0.3 功能函数
sleep
function sleep(milliSeconds){
var startTime =new Date().getTime();
while(new Date().getTime() < startTime + milliSeconds);
}
exec
import { exec } from "child_process";
exec("find /home/satone/",function(error, stdout, stderr){
response.writeHead(200,{"Content-Type":"text/plain"});
response.write(stdout);
response.end();
});
1. 学习资料
1.1 主要资料
1.2 辅助资料
2. 介绍
服务端的JavaScript,使用Google的V8虚拟机(Google的Chrome浏览器使用的JavaScript执行环境)来解释和执行JavaScript代码。
2.1 模块化编程
模块化编程是Node.js的重要思想,它让JavaScript的大规模工程成为可能。
2.1.1 export导出模块接口
// a.js
export default function() {}
export function a () {}
var b = 'xxx';
export {b}; // 这是ES6的写法,实际上就是{b:b}
setTimeout(() => b = 'ooo', 1000);
export var c = 100;
export在导出模块时,必须与模块内部的变量具有一一对应的关系。export 1
没有任何意义,也不可能在import的时候有一个变量与之对应,var a = 1; export a
虽然看上去成立,但是a的值是一个数字,根本无法完成解构,因此必须写成export {a}
的形式。即使a被赋值为一个function,也是不允许的。而且,大部分风格都建议,模块中最好在末尾用一个export导出所有的接口,例如:export {fun as default,a,b,c};
2.1.2 require导入(旧)
var http = require("http")
2.1.3 import导入(新)
import导入的语法与require不同,而且必须放在文件的最开始,前面不允许有任何逻辑代码。
import $ from 'jquery';
import * as _ from '_';
import {a,b,c} from './a';
import {default as alias, a as a_a, b, c} from './a';
import后跟上花括号是基本用法,花括号里的变量与export后面的变量一一对应。
2.1.4 as关键字
与Python中as的用法类似:取别名。
当需要从不同的模块中导入名字相同的函数时,可以用as来取别名避免冲突。
2.1.5 default关键字
default是别名的语法糖
// d.js
export default function() {}
// 等效于:
function a() {};
export {a as default};
这个语法糖的好处是在import的时候可以省去花括号。例如:
import $,{each,map} from 'jquery';
import后面的第一个$
是{default as $}
的替代写法。
2.1.6 *符号
*是代表所有,只在import中使用。
import * as _ from '_';
在意义上和import _ from '_';
是不同的,虽然实际上后面的使用方法是一样的。它表示的是把'_'
模块中的所有接口挂载到_
这个对象上,所以可以用_.each
调用某个接口。
一般不建议使用*符号进行导入,除非确实要使用到被导入模块内的所有接口,否则建议用花括号进行导入,用一个导入一个。
2.1.7 require OR import ?
- require是赋值过程,可以在任何需要的时候获得导入模块的任何接口,甚至不需要变量来中转。
- import是解构过程,只需要编译导入部分的代码,具有更高的性能。而且是较新的标准,建议使用。
3 构建应用模块
import { createServer } from "http";
createServer(function(request, response){
response.writeHead(200,{"Content-Type":"text/plain"});
response.write("Hello World");
response.end();
}).listen(8888);
console.log("server start at http://127.0.0.1:8888");
3.1 基于事件驱动的回调
Question: 在我们的Node.js程序中,当一个新的请求到达8888端口的时候,我们怎么控制流程呢?
- 创建了服务器,并且传递了一个匿名函数,无论何时服务器收到一个请求,这个函数就会被调用。
- 我们不知道请求什么时候会发生,但是我们现在有了一个处理请求的地方:它就是我们传递过去的那个函数。
- 这就是“回调”。我们给某个方法传递了一个函数,这个方法在有相应事件发生的时候调用这个函数来进行“回调”。
理解:在上文示例的代码中,创建服务器并开始监听之后,还在终端打印了一句话,运行该代码文件,会发现代码并不会停在createServer().listen();
这行,而是继续往下执行了并在终端进行了打印。但监听8888端口的函数仍然是有效的,当8888端口出现请求时,服务器会回调并执行传递至createServer()
的函数。
相似的现象(Q)
setTimeout(() => {
console.log("timeout:2s");
}, 2000);
console.log("after timeout");
的输出为:
after timeout
timeout:2s
是否也属于回调?
3.2 服务器是如何处理请求的
当回调启动,匿名函数被触发时,有两个传入参数:request, response。
它们是对象(object),可以使用它们的方法来处理HTTP请求的细节并响应请求。
在该例中,收到请求时,使用response.writeHead()
函数返回一个HTTP状态200和HTTP头的内容类型(content-type),使用 response.write()
函数在HTTP相应主体中发送文本“Hello World"。
最后调用response.end()
完成相应。
在该例中没有使用到request对象。
3.3 路由
对于不同的URL请求,服务器应该有不用的反应。
我们需要的数据都会包含在request对象中,但是为了解析这些数据,需要额外的nodejs模块,分别是url和querystring模块。
url.parse(string).query
|
url.parse(string).pathname |
| |
| |
------ -------------------
http://localhost:8888/start?foo=bar&hello=world
--- -----
| |
| |
querystring(string)["foo"] |
|
querystring(string)["hello"]
使用路由的server.js文件:
import { createServer } from "http";
import { parse } from "url";
import { route } from "./router.js";
function start() {
createServer(function(request, response){
var pathname = parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
route(pathname);
response.writeHead(200,{"Content-Type":"text/plain"});
response.write("Hello World");
response.end();
}).listen(8888);
console.log("server start at http://127.0.0.1:8888");
}
export { start };
文件结构:
文件名 | 功能 | import | export |
---|---|---|---|
index | main文件 | ./server,./router,./requestHandlers | null |
server | 启动服务器 | http,url | serverStart |
routers | 路由 | null | route |
requestHandlers | 相应请求,路由分发后实际执行的函数 | null | 各函数 |
3.4 阻塞与非阻塞
参考资料:理解node.js的事件轮询
一个请求长时间的计算会阻塞后面的请求,需要进行非阻塞操作。
2020年8月4日 19:30:27 进度:“以非阻塞操作进行请求响应” 资料
3.4.1 以非阻塞操作进行请求响应
使用exec
创建子进程,并将返回响应也放在子进程中进行。
3.5 POST请求
通过给request对象添加监听的方式获取POST请求的内容
3.6 阻塞对比非阻塞一览
本小节资料来自:阻塞对比非阻塞一览 | Node.js
阻塞 是指在 Node.js 程序中,其它 JavaScript 语句的执行,必须等待一个非 JavaScript 操作完成。这是因为当 阻塞 发生时,事件循环无法继续运行 JavaScript。
在 Node.js 中,JavaScript 由于执行 CPU 密集型操作,而不是等待一个非 JavaScript 操作(例如 I/O)而表现不佳,通常不被称为 阻塞。在 Node.js 标准库中使用 libuv 的同步方法是最常用的 阻塞 操作。原生模块中也有 阻塞 方法。
在 Node.js 标准库中的所有 I/O 方法都提供异步版本,非阻塞,并且接受回调函数。某些方法也有对应的 阻塞 版本,名字以 Sync 结尾。
阻塞 = 同步
非阻塞 = 异步
以文件系统做例子,同步文件读取:
const fs = require('fs');
const data = fs.readFileSync('/file.md'); // blocks here until file is read
console.log(data);
moreWork(); // will run after console.log
异步:
const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
if (err) throw err;
console.log(data);
});
moreWork(); // will run before console.log
在同步例子中,morework()
会在data读取完后再调用;而在异步的例子中,将不会等待文件读取,直接执行morework()
,当文件读取完毕后再回调输入readFile
的匿名函数。异步方法可以提高吞吐量。
3.6.1 阻塞与非阻塞操作混用的危险
需要注意在非阻塞操作之后的代码,都可能先于非阻塞操作中的代码执行,注意考虑可能造成的影响。
可以将相关的操作都嵌套在非阻塞操作中。
重新编辑于:2020-08-06 13:16:05