【问题标题】:chaining javascript functions链接javascript函数
【发布时间】:2015-02-21 06:22:40
【问题描述】:

我在SO上搜索了这个话题一个多小时,找不到像我这样的案例。

我有一个基于 Ruby on Rails 开发的 Web 应用程序。它基于具有多个字段和按钮的表单来执行操作。

这些是示例(我的真实应用程序使用更多功能和更多操作组合): 当 Field1 改变时,我想执行 JS 函数 function1(),然后是 function2(),然后是 function3()。 当 Field2 改变时,我想执行 JS 函数 function2(),然后是 function3()。 当Field3改变时,我想执行JS函数function3()。

所有这些 JS 函数调用在我的控制器中定义的特定操作,并使用 AJAX 更新表单。我希望function2()只有在function1()更新完表单后才开始执行,否则结果会出错。

由于这些函数调用的控制器方法将 API 调用发送到许多其他网站,例如 Google 地理编码或 Google 时区,它们的响应时间是不可预测的,可能从几百毫秒到几秒不等。

我试过了:

onchange="function1();function2();function3()"

但这不起作用,因为 function2() 在 function1() 通过 AJAX 完成更新之前开始执行,并且 function3() 与 function2() 的问题相同。

我也试过了:

onchange="function1();setTimeout(function(){function2();setTimeout(function(){function3()},FUNCTION2_DELAY)},FUNCTION1_DELAY)"

但这也不起作用,因为如果 FUNCTION1_DELAY 设置得太长,function2() 将不会在 FUNCTION1_DELAY 过期之前开始执行,而 function1() 可能执行得比 FUNCTION1_DELAY 快得多,如果 FUNCTION1_DELAY 设置得太短,function2( ) 将在 function1() 完成 function2() 运行所需的更新之前开始执行。 function3() 与 function2() 的情况相同。

我的问题是:有没有更聪明的方法让 function2() 仅在 function1() 通过 AJAX 完成更新表单时才开始执行,并且对于 function3() 关于 function2() 也是如此? 我知道我可以创建新的控制器方法来合并这些函数,例如将 function1()、function2() 和 function3() 合并到 new_function1()、...等中,但这会使我的代码包含重复的操作,最终会使其更难维护。所以我宁愿寻找一种更聪明的方法来处理这个问题。

【问题讨论】:

  • ajax 是异步的。如果不使用 Promise 或使用连续请求的成功回调来调用下一个函数,则无法连续调用这些函数。您可能想研究链接 ajax 承诺。如果没有看到您的代码,很难提供更多帮助
  • @JRulle:感谢您的回答。我看了那个,我的不是重复的,因为没有一个例子使用 AJAX。在我的例子中,当 function1 在浏览器上完成执行时,它仍然需要等待 AJAX 更新,然后 function2 才能正确执行。所以function1的执行结束并不是在发送AJAX请求时,而是从服务器接收回来的。我希望这可以澄清差异。

标签: javascript jquery ajax


【解决方案1】:

你需要使用 Promises。

基本上是这样工作的:

var MyFunction1 = new Promise(
    function() {
        //do stuff here
    }
);

MyFunction1.then(Myfunction2 ...).then(Myfunction3 ...;

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise http://api.jquery.com/promise/

【讨论】:

    【解决方案2】:

    setTimeout 是异步的,所以这不起作用。您可以在函数 1 的末尾调用函数 2,但仍在函数内部。对于函数 3 也是如此:

    function one(){
      ...logic...
      function two();
    }
    
    function two(){
      ...logic...
      function three();
    }
    
    function three(){
      ...logic...
    }
    

    或者,您可以创建某种函数队列,并且仅在当前函数完成时才移动到下一个:

    var functionQueue = [
      one,
      two,
      three
    ];
    
    function next(){
      var nextFn = functionQueue.shift();
      if( nextFn ){
        nextFn();
      }
    }
    
    function one(){
      ...logic...
      next();
    }
    // same for two & three
    

    你也可以使用promises,它非常强大,可以让代码更清晰易读,但是对于这个问题可能有点过头了

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-17
      • 1970-01-01
      • 1970-01-01
      • 2015-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多