NodeJS总结(二):事件响应一定是异步的吗?

来源:互联网 发布:自适应pid控制算法 编辑:程序博客网 时间:2024/06/02 19:13

事件驱动编程是一种程序流程取决于事件发生次序的编程风格,我们只需要为事件的处理程序注册回调函数,那么在事件发生时,系统就会自动调用这些处理程序,这种编程风格又叫作后继传递风格(Continue-Passing Style,CPS)。

因为事件具有不可预知的特性,再加上异步与事件的阐述的亲近性,所以很多人都想当然地认为,事件响应一定都是异步的,例如AJAX、setTimeout,如下:

//  #! /usr/local/bin/node//  计划以bash的方式直接运行//  获取事件注册对象const EventEmitter = require('events').EventEmitter//  创建事件对象,可以理解为普通的JS对象let customEvent = new EventEmitter()//  赋初始值Object.assign(customEvent, {    username : 'yiifaa'})//  设置定时任务setTimeout(() => {    console.log(customEvent.username)}, 0)//  改变初始值customEvent.username = 'yiifee'

在上面的代码中,因为javascript执行引擎会把定时任务添加到事件队列中,并不会立即执行,所以输出的结果是未改变的值yiifaa,而不是yiifee。这样的结果更加深了我们的印象,事件响应一定是异步的,真的吗?继续下面的例子,我们添加自定义事件:

const EventEmitter = require('events').EventEmitter//  初始化对象let customEvent = new EventEmitter()Object.assign(customEvent, {    username : 'yiifaa'})//  注册事件customEvent.on('change', function (age) {    console.log(this.username)})//  触发事件customEvent.emit('change', 20)//  改变初始值customEvent.username = 'yiifee'

如果事件响应是异步的,那么上面的输出结果依旧是yiifee(主线程中的代码优先执行),但很遗憾,结果却是yiifaa,这充分说明,事件响应并不一定总是异步的,而且从我们实践中的效果来看,所有的事件响应都是同步的,这也是监听者模式的特性(监听者模式是单线程环境下的顺序执行模型)。

我们再看一个在DOM中注册事件的例子,确认事件响应到底是异步的还是同步的,如下:

<h1 id="output">yiifaa</h1><script>    var output = document.querySelector('#output')    //  注册事件    output.addEventListener('click', () => {        console.log('yiifaa')    })    //  触发事件    output.click()    console.log('yiifee')</script>

在上面的例子中,输出结果依旧是“yiifaa yiifee”,这说明即使是在DOM编程中,事件响应也是同步执行的。

仔细观察上面的例子,我们发现,事件响应代码的执行位置,取决于我们事件的激发位置,所以我们可以大胆地推测,事件处理引擎都把事件激发的代码摆放在当前主线程之外,所以只有主线程的代码执行完成后,才会出现事件的执行结果,如代码1。

结论

在单线程的环境下,事件响应一定是同步的,之所以会出现异步的效果,这是由于单线程的执行线程无法中断,所以事件处理引擎会把事件激发的代码摆放在主线程之外。

原创粉丝点击