Node.js 个人课程笔记

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

child_process 子进程|文档

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. Node初学者入门 | 简书
  2. Node.js 教程 | 菜鸟教程

1.2 辅助资料

  1. Node中的require和import
  2. 阻塞对比非阻塞一览 | Node.js

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端口的时候,我们怎么控制流程呢?

  1. 创建了服务器,并且传递了一个匿名函数,无论何时服务器收到一个请求,这个函数就会被调用。
  2. 我们不知道请求什么时候会发生,但是我们现在有了一个处理请求的地方:它就是我们传递过去的那个函数。
  3. 这就是“回调”。我们给某个方法传递了一个函数,这个方法在有相应事件发生的时候调用这个函数来进行“回调”。

理解:在上文示例的代码中,创建服务器并开始监听之后,还在终端打印了一句话,运行该代码文件,会发现代码并不会停在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 };

文件结构:

文件名功能importexport
indexmain文件./server,./router,./requestHandlersnull
server启动服务器http,urlserverStart
routers路由nullroute
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

child_process 子进程|文档

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. Node初学者入门 | 简书
  2. Node.js 教程 | 菜鸟教程

1.2 辅助资料

  1. Node中的require和import
  2. 阻塞对比非阻塞一览 | Node.js

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端口的时候,我们怎么控制流程呢?

  1. 创建了服务器,并且传递了一个匿名函数,无论何时服务器收到一个请求,这个函数就会被调用。
  2. 我们不知道请求什么时候会发生,但是我们现在有了一个处理请求的地方:它就是我们传递过去的那个函数。
  3. 这就是“回调”。我们给某个方法传递了一个函数,这个方法在有相应事件发生的时候调用这个函数来进行“回调”。

理解:在上文示例的代码中,创建服务器并开始监听之后,还在终端打印了一句话,运行该代码文件,会发现代码并不会停在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 };

文件结构:

文件名功能importexport
indexmain文件./server,./router,./requestHandlersnull
server启动服务器http,urlserverStart
routers路由nullroute
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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值