如何处理可以多次触发的同一事件的两个回调之间的竞争?

问题描述 投票:0回答:1

我有两个回调需要放在同一个项目的同一个

change
事件上。由于不值得讨论的原因,我需要将这些回调放在单独的
on
中,我无法将它们统一在单个
on
调用下。 所以我需要这些
on
调用来保持独立
,例如:

$('body').on('change', '#my-div', function1);
$('body').on('change', '#my-div', function2); 

现在,我内部有一个 AJAX 调用

function1
。我希望
function2
始终在
function1
执行完成后执行,包括在
function1
内收到 AJAX 响应之后。我询问了 ChatGPT,它建议我使用
$.Deferred()
:

let function1Deferred = $.Deferred();
function function1() {
    function1Deferred = $.Deferred();
    $.ajax({
        url: 'your-url', // Replace with your URL
        method: 'GET',
        success: function(data) {
            console.log("Function1 AJAX request completed");
            function1Deferred.resolve(); 
        },
        error: function() {
            function1Deferred.reject();
        }
    });
}

function function2() {
    function1Deferred.done(function() {
        console.log("Function2 is now executing after function1 has completed.");
    });
}

不过,在我看来,这只能在第一次触发

change
事件时解决问题,因为不能保证
function1
会在
function2
之前先运行 - 因此不能保证在第二次触发以及
change
事件的第三个触发器等,
function1Deferred = $.Deferred();
内的
function1
行将在
function2
运行之前运行,因此
function2
很可能是第一个运行的,并在后续运行时运行到最后
change
事件的触发器。

我是否遗漏了一些东西,代码是否真正实现了我想要的效果,而我只是遗漏了一些关于

Deferred
在幕后如何工作的信息?如果是的话,我错过了什么?如果没有,我该如何解决我的问题并确保
function2
始终在事件的后续触发器上运行在
function1
之后,而不仅仅是在第一个事件上?

我只是想再次强调,我需要

on
函数的调用保持独立,我不能使用单个
on('change', '#my-div', newFunction)
调用,这不是在更大的上下文中解决我的问题的解决方案。

javascript jquery race-condition
1个回答
0
投票

如所呈现的,代码不一定会执行您想要的操作。如果

function2
首先触发:

  • 第一次,它会引用初始的延迟对象,该对象永远不会完成,所以函数2永远不会运行;
  • 在后续运行中,它将引用上一次运行中已完成的延迟对象,因此它将在函数 1 之前运行。

这里是 a demo,它将延迟对象显式设置为

null
以使其更加明显。如果单击“运行 F2+F1”按钮,您将收到“function1Deferred is null”错误。

考虑到限制,最简单的选择可能是将

function2
主体包装在
setTimeout
调用中:

setTimeout(() => function1Deferred.done(() => {
    output.append("Running function 2\n");
}), 0);

这会将控制权返回给调用函数,从而允许其他处理程序在延迟对象上注册

done
回调之前执行。

更新了演示

现在,无论您单击哪个按钮,直到出现“功能 1 完成”消息之后,您才会看到“正在运行功能 2”消息。

© www.soinside.com 2019 - 2024. All rights reserved.