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

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

结论

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值