【发布时间】:2014-01-16 18:06:33
【问题描述】:
最奇怪的事情刚刚发生在我身上。我有一些 javascript 似乎以错误的顺序执行。这把我吓坏了!观察:
代码
handleKeyDown: function (e) {
console.log("handleKeyDown");
var key = e.which;
var text = this.ui.$input.val();
if (_.isFunction(this[key])) {
// call the appropriate handler method
this[key](text, e);
console.log("before announceEdits");
this.announceEdits();
}
if (key === ENTER || key === ESC) {
console.log("fired field:key:down");
this.trigger("field:key:down", { editable: this, restore: (key === ESC) });
}
},
announceEdits: function () {
console.log("announceEdits");
var edits = this.getEdits();
console.log("edits: %o", edits.data);
console.log("fired field:edits");
this.trigger("field:edits", edits);
},
/* gather all the existing taggies */
getEdits: function () {
var data = this.$taggies().map(function (index, taggy) {
return $(taggy).data("value");
}).toArray();
var edits = {
attribute: "tags",
data: data
};
return edits;
},
当我运行这段代码时,函数似乎被乱序执行。这是上述代码在 Firefox 控制台中的输出:
输出
请注意,我们在得到announceEdits 之前很久就得到了before announceEdits,这是annouceEdits 函数的第一行......我对世界的理解让我相信这是错了。
我做了什么
现在,我考虑了以下几点:
- 可能正在缓冲控制台语句或类似情况,导致它们出现乱序。
- 这可能与 MarionetteJS 处理事件的方式有关。
相信这可能是奇怪的事件,我尝试删除对触发的调用(只需注释掉触发事件的行)。删除触发器后,日志语句仍然出现乱序。所以它似乎不是由 MarionetteJS 的事件实现引起的(也就是说,BackboneJS 的事件实现^o^//)。
我也被引导相信这不是日志语句缓冲区问题,因为事件本身是无序处理的(即我希望在处理第一个事件后拥有的数据不是按顺序排列的处理第二个事件的时间)。这会导致代码以我想要的方式“不起作用”(但是,请参见下文)。
在我的探索中,我试图缩小范围。我因此修改了代码,以简化代码:
if (_.isFunction(this[key])) {
// call the appropriate handler method
this[key](text, e);
console.log("before announceEdits");
console.log("announceEdits");
var edits = this.getEdits();
console.log("edits: %o", edits.data);
console.log("fired field:edits");
this.trigger("field:edits", edits);
}
这样我就不会陷入子程序。运行此代码,控制台语句以正确的顺序出现。更有趣的是,在这种情况下,事件也会按照我期望的顺序被触发和处理!此代码有效,但带有子例程的代码无效。
我尝试创建此代码的小提琴,但 jsfiddle 似乎不喜欢 Backbone(我尝试将该库作为外部库包含在内,但这似乎不起作用)。我确实创建了this fiddle,只是为了让自己放心,世界上的某个地方仍然有一块正常的岩石。
更新:我更改了小提琴,以便主函数本身就是一个处理程序。在小提琴中一切仍然正常。
我认为这个世界是如何运作的
函数创建执行完成的堆栈帧。如果一个函数调用另一个函数,则会将一个新的堆栈帧推入堆栈。如果一个函数触发一个事件,它会创建一条消息,该消息被推送到消息队列中。每当(我不清楚)堆栈为空时,队列中的下一条消息就会弹出,然后调用该消息的所有处理程序。
在这个模型中,毫无疑问,事件应该按照我期望的顺序发生(第二个清单的顺序)。我们应该先下到announceEdits,将field:edits消息推送到队列中,然后弹回并推送field:key:down消息。然后field:edits 的处理程序应该运行,最后是field:key:down 的处理程序。
问题
是否有任何可能导致这些函数无序执行?或者更有可能:有什么可能导致这些函数看起来被无序执行?
如果我的理解有问题:我哪里出错了?
如果这最终是由拼写错误引起的,请记住,我们都是程序员,有时我们都会扯掉头发并在阴影中咆哮。
【问题讨论】:
-
handleKeyDown?我怀疑这就是问题所在;您正在添加一个事件。尝试在this.announceEdits()周围添加 1ms 的setTimeout -
这里有一个很好的解释stackoverflow.com/questions/12051769/…。具有讽刺意味的是,最差的答案是我的,并且被接受了,但第二个答案有一些很好的见解。
-
啊!我正在处理一个事件!哦,伙计们!我环顾四周,寻找就在我脚下的答案!好的,告诉我更多!
-
很难说发生了什么,真的。可能是
trigger或keyDown事件,或一些异步代码......不确定,但我会尝试跟踪调用堆栈;放置一些断点并查看执行顺序到底是什么,并在调试时尝试设置 1ms 超时以查看是否得到正确的顺序。一旦找到罪魁祸首,解决问题就会更容易。 -
你可能没有在你的小提琴中包含下划线,你需要下划线然后是 Backbone:jsfiddle.net/ambiguous/RRXnK
标签: javascript events backbone.js