目录
概要
node由于是单线程异步,还有一些概念需要补充,才能更好地应用在实际生产中
例如:闭包,时间控制,事件驱动,异步,promise,await/async ,回调,瀑布模型等内容需要了解。
简单介绍
0. 闭包(closure)
我自己的理解(不一定准确)就是实现数据所在位置(最近的花括号)的私有化,正常来讲,花括号内的变量可以互相使用,但是花括号外的数据或者方法不能使用该花括号内的数据,即是闭包。如,函数的内嵌函数 可以引用外层函数的变量,反之则不行,就是闭包。
为什么要有闭包?在node中单线程的程序异步执行,这并不符合通常的逻辑,如 使用var 声明变量node会 预解析 ,声明可以被默认提升到最顶部,但是变量的赋值又不支持提升,赋值顺序不对就会报undefined。var可以多次声明同一个变量(日常中应该减少这种使用)。 function 函数名的声明和函数体的绑定是一次完成的,所以函数的闭包就是内嵌函数。闭包常用于函数柯里化,防抖 ,节流等
1. 定时器
这里简单介绍setTimeout的使用 ,后期有需要再进行补充
setTimeout(() => {
console.log("settimeout 5000") ;
}, 5000);
console.log("settimeout test") ;
结果如下:
2. 回调(callback)与异步 (Async )
Node.js 异步编程的直接体现就是回调。
异步编程依托于回调来实现,但不能说使用了回调后程序就异步化了。
回调函数在完成任务后就会被调用,Node 使用了大量的回调函数,Node 所有 API 都支持回调函数。
例如,我们可以一边读取文件,一边执行其他命令,在文件读取完成后,我们将文件内容作为回调函数的参数返回。这样在执行代码时就没有阻塞或等待文件 I/O 操作。这就大大提高了 Node.js 的性能,可以处理大量的并发请求。
回调函数一般作为函数的最后一个参数出现
在之前的 定时器 介绍中,首先执行了下面的函数,后执行延时5秒打印的函数。这也是异步的一种。node都是进行异步操作,如果希望进行同步执行,就需要进行回调(callback)操作。在下面的范例中都是。
- 定时器
- 建立网络连接
- 读取网络流数据
- 向文件写入数据
- Ajax提交
- 请求数据库服务
异步 Async
为避免代码陷入回调地狱,引入了 异步方法 async/await 方式返回一个promise对象,使用then方法获取promise中的信息 。专栏文章 参考后可以发现,使用 async/await 方式可以实现同步的结果。测试代码如下:
/**
* 传入参数 n,表示这个函数执行的时间(毫秒)
* 执行的结果是 n + 200,这个值将用于下一步骤
*/
function takeLongTime(n) {
return new Promise(resolve => {
setTimeout(() => resolve(n + 2000), n);
});
}
function step1(n) {
console.log(`step1 with ${n}`);
return takeLongTime(n);
}
function step2(n) {
console.log(`step2 with ${n}`);
return takeLongTime(n);
}
function step3(n) {
console.log(`step3 with ${n}`);
return takeLongTime(n);
}
async function doIt() {
console.time("doIt");
const time1 = 3000;
const time2 = await step1(time1);
const time3 = await step2(time2);
const result = await step3(time3);
console.log(`result is ${result}`);
console.timeEnd("doIt");
}
doIt();
3. 事件 events
事件循环:可以理解为对node中的异步API(定时器,I/O操作,node独有)分别加入不同的队列(Timer Poll Check),同步代码执行完毕后,事件循环不停执行,在Poll队列阻塞(希望优先处理I/O异步操作事件),异步API开始进入对应的队列,执行异步API事件。
EventEmitter(类似listener) 事件模块 监听器注册顺序就是执行顺序、可以使用prependListener 实现插入在最前方的监听器。emit触发的默认是同步的,涉及异步需要将emit方法写入nextTick中。
events 被引入后,events 模块只提供了一个对象:events.EventEmitter,新建EventEmitter对象, 一般使用on方法绑定函数, emit 方法实现触发。示例代码:
const events = require('events') ;
var eventEmitter = new events.EventEmitter() ;
eventEmitter.on("start",eventHandler) ;
eventEmitter.on("ds",eventDs);
function eventHandler(){
console.log("handler") ;
eventEmitter.emit("ds") ;
}
function eventDs(){
console.log("ds2018") ;
}
eventEmitter.emit("start") ;
简单补充应用
Promise 是JavaScript知识的重点,用以解决回调函数多层嵌套的问题,也是async的重要前置。 0. 定时器需要传入回调函数作为参数,数组的一些高级方法也需要传入回调函数(foreach)。 回调函数分为 同步回调(数组高级遍历) 与 异步回调。
同步回调:
小结
。