异步I/O

对于异步I/O,在前端coding领域内,基本上是司空见惯的了,前端coding与其他的GUI编程一样,大部分是基于界面的,针对事件的回调编程模式来进行的编程,无非就是设置一个监听器,然后在事件响应的时候,触发这个监听器。 在操作系统层面,异步I/O主要是通过信号量、消息等方式来实现的! 而对于之前的关于nodejs的相关学习,可以得知,在nodejs中的

nodejs的异步I:O

生产/消费模式的异步I/O

如上所示,在node中的异步I/O,无非就是一个js主线程以及一个异步线程的通讯机制而已,nodejs发起一个异步调用之后,直接返回调用后的结果(这里我们可称之为fid),然后继续执行其他js主线程的任务,而异步I/O的动作,则交给 nodejs所处的环境系统来执行,这里 :u6709: 可能 :u6709: 多个异步I/O操作,然后在每个异步I/O动作执行完毕之后,异步I/O通知原时间监听者,然后通过fid来进行I/O结果数据的一个传输。

:warning: 在node中,它的一个程序的执行模型:事件循环,在使用node执行一个程序的时候,其实它启动了一个while(true)的事件循环机制,每执行一个循环,我们称之为一个tick,每个tick的过程就是从事件队列中查看是否 :u6709: 要处理的事件,如果有则取出来,并执行相关的回调动作,然后进入下一个循环,如果不在有事件的话,则退出进程,流程如下:

事件循环过程

:point_up: 这里其实仅仅只是一个消费者消耗事件的过程,应该还有更前面的一个过程:

事件生产者

:stars: 在异步I/O中,其实就是一个设计模式:生产者/消费者模式,关于该模式所涉及的相关角色有:生产者、消费者、观察者,这里的观察者就是每一个回调,而每次的tick则是消费者,而生产者就是一次次的异步I/O完成动作, 将上述的几个操作给结合起来,就有如下的一个完整的node的异步I/O的流程: node异步IO流程

非I/O的异步API

在node存在着一些与I/O无关的异步API,它们分别是:setTimeout()setInterval()setImmediate()process.nextTick() 它们的实现原理与异步I/O类似,只不过是不需要I/O线程池的参与

定时器(setTimeout和setInterval)

这两者与浏览器中中的API是一致的,分别用于单词和多次定时执行任务的动作。

setTimeout的调用过程

:star2: 调用setTimeout或者setInterval会创建一个定时器,然后将定时器插入到观察者内部的一颗红黑树中,每次Tick执行时,会从该 红黑树中迭代取出定时器对象,检查是否超过规定的时间,如果超过了,就形成一个事件,立即执行它的回调函数。 :warning: 这里 :u6709: 一个需要注意的是,设置的定时器不一定能够百分百按照预定的时间之后来执行,因为假如当前的CPU执行时间正在被占用, 然后定时器回调刚好被执行,由于js单线程的原因,必须要等到当前任务执行完毕之后,回调函数才会被执行!!!

process.nextTick

与setTimeout(fn, 0)的相比,process.nextTick显得非常轻量级,关于process.nextTick的代码如下: ```javascript // lib/internal/process/task_queue.js/103行 function nextTick(callback) { validateFunction(callback, 'callback');

if (process._exiting) return;

let args; switch (arguments.length) { case 1: break; case 2: args = [arguments[1]]; break; case 3: args = [arguments[1], arguments[2]]; break; case 4: args = [arguments[1], arguments[2], arguments[3]]; break; default: args = new Array(arguments.length - 1); for (let i = 1; i < arguments.length; i++) args[i - 1] = arguments[i]; }

if (queue.isEmpty()) setHasTickScheduled(true); const asyncId = newAsyncId(); const triggerAsyncId = getDefaultTriggerAsyncId(); const tickObject = {

[async_id_symbol]: asyncId,
[trigger_async_id_symbol]: triggerAsyncId,
callback,
args

}; if (initHooksExist()) emitInit(asyncId, 'TickObject', triggerAsyncId, tickObject); queue.push(tickObject); }

<img align='absmiddle' alt=':star2:' class='emoji' src='/gitbook/gitbook-plugin-advanced-emoji/emojis/star2.png' title=':star2:' /> 这里nextTick执行的时候,仅仅是创建一个事件对象,然后塞到事件队列中,等待在下一次的tick被执行,因此它的效率,要比setTimeout要高!

#### setImmediate
> 该方法与nextTick类似,都是将回调函数延迟执行,但是两者之间有微妙的区别,如下代码所示:
```javascript
process.nextTick(function(){
        console.info("nextTick延迟执行");
});
setImmediate(function(){
        console.info("setimmediate延迟执行");
});
console.info("js主线程执行");

nextTick与setImmediate

:stars::point_up_2: 可以看出process.nextTick的优先级要高于setImmediate

results matching ""

    No results matching ""