我有以下代码:
let bindings =
{
on : (messageName,callback) =>
{
bindings[messageName] = callback
}
}
bindings.on('test',(params) =>
{
setTimeout( () =>
{
console.log("call id " , params.callId)
},~~(Math.random()*100))
})
let data = {callId : 1 }
for (let i=0;i<5;i++)
{
bindings['test'](data)
data.callId++
}
它产生输出
call id 6
call id 6
call id 6
call id 6
call id 6
call id 6
我知道这个问题可以通过绑定 https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Function/bind 来解决,但我找不到正确的方法来实现它并保持实际设计
添加一个常量可以解决问题,但我想找到一种更优雅/通用的方式来解决问题
bindings.on('test',(params) =>
{
const callId = params.callId
setTimeout( () =>
{
console.log("call id " , callId)
},~~(Math.random()*100))
})
它不是关于事件逻辑的实现,而是关于使用循环更新的引用调用它。
由于内部setTimeout
,该实现是异步执行,因此调用循环在执行第一个事件逻辑之前完全执行。因此,由于输入params
是对对象data
的引用,当循环完成时,callId
值现在是6,当被任何异步调用引用时,该值将是该值。
本质上,for
循环是排队 5 个异步操作,其中每个操作都使用相同的引用对象,data
.循环还会为每次迭代更新data
对象的属性值。由于 JavaScript 处理异步操作的方式,循环将在任何异步操作开始之前完成,因为它仍然遵循脚本的初始同步执行。
解决此问题的一种方法是为每个循环迭代创建一个新的输入对象:
let bindings = {
on: (messageName, callback) => {
bindings[messageName] = callback
}
}
bindings.on('test', (params) => {
setTimeout(() => {
console.log("call id ", params.callId)
}, ~~(Math.random() * 100));
});
for (let i = 0; i < 5; i++) {
bindings['test']({callId: i + 1});
}