【问题标题】:Call a function after previous function is complete前一个函数完成后调用一个函数
【发布时间】:2011-06-27 09:22:04
【问题描述】:

我有以下 JavaScript 代码:

$('a.button').click(function(){
    if (condition == 'true'){
        function1(someVariable);
        function2(someOtherVariable);
    }
    else {
        doThis(someVariable);
    }
});

如何确保只有在function1 完成后才调用function2

【问题讨论】:

  • function1 正在执行异步操作吗?
  • Yads,如果 function1 包含动画,则 function2 将在 function1 的动画仍在发生时执行。你如何让 function2 等到 function1 中启动的所有内容都完成?
  • 有人可以向我解释为什么需要做任何事情来确保在 function1 完成之前不会调用 function2 吗?这里没有发生异步操作,所以 function2 在 function1 完成之前不会运行,因为这个操作是同步的。

标签: javascript jquery


【解决方案1】:

指定一个匿名回调,并让function1接受它:

$('a.button').click(function(){
    if (condition == 'true'){
        function1(someVariable, function() {
          function2(someOtherVariable);
        });
    }
    else {
        doThis(someVariable);
    }
});


function function1(param, callback) {
  ...do stuff
  callback();
} 

【讨论】:

  • +1 但如果他使用 1.5,他可以使用新的 Deferreds 模式
  • 感谢您的快速回复。是的,function1 只是执行一个简单的异步任务,所以我相信你是对的,因为我必须创建一个回调——或者看看 philwinkle 提到的这个延迟业务。再次感谢各位。我要睡一觉,早上再解决这个问题。
  • 这个答案不是解决方案。这是它不起作用的证据:jsfiddle.net/trusktr/M2h6e
  • @MikeRobinson 问题是:如果...do stuff 包含异步内容怎么办? Function2 仍不会按预期触发。我上面评论中的示例表明,由于foo() 函数中包含异步代码,bar() 在执行完foo() 的内容后不会触发它的内容,即使使用$.when().then() 在其他。仅当(且仅当)您的代码中 ...do stuff 处的所有内容都严格同步时,此答案才有效。
  • @trusktr 在这种情况下,您需要继续将第一个回调传递到第 n 级异步调用,然后在所有 ncallBack() /i> 异步调用完成。由于 OP 没有提到他在函数中所做的事情,因此将其假定为一级异步调用。
【解决方案2】:

如果您使用的是 jQuery 1.5,您可以使用新的 Deferreds 模式:

$('a.button').click(function(){
    if(condition == 'true'){
        $.when(function1()).then(function2());
    }
    else {
        doThis(someVariable);
    }
});

编辑:更新博客链接:

丽贝卡墨菲在这里写了一篇很棒的文章:http://rmurphey.com/blog/2010/12/25/deferreds-coming-to-jquery/

【讨论】:

  • 但这是一个可行的例子吗?什么被推迟?您正在立即执行 function1 和 function2。 (我不是最初的评论者。)
  • 这对我来说根本不起作用。 function1 和 function2 都在完全相同的时间执行(如人眼所见)。这是一个小例子:jsfiddle.net/trusktr/M2h6e
  • Rebecca Murphy 的文章是在将 Defferds 引入 jQuery 之前编写的,它使用了基于作者认为将如何实现的示例。请访问 jQuery 的站点以了解如何实际使用此功能:api.jquery.com/jQuery.Deferred
  • 即使使用 jQuery 1.5 或其他现代版本,您不想要 $.when(function1).then(function2);(没有调用函数的括号)吗?
  • 晚了几年才读到这些cmets。 function1 应该返回一个承诺。在这种情况下,它需要是实际执行的函数,而不是引用。当resolve 在该承诺上被调用时,function2 被执行。这很容易通过假设function1 有一个ajax 调用来解释。然后done 回调将解决该承诺。我希望这很清楚。
【解决方案3】:

试试这个:

function method1(){
   // some code

}

function method2(){
   // some code
}

$.ajax({
   url:method1(),
   success:function(){
   method2();
}
})

【讨论】:

  • 在测试了其他几个解决方案后,终于对我有用了:) 谢谢@TuanTruong!您可以添加一些文本以使此答案对遇到相同问题的其他用户也更有用。
【解决方案4】:

此答案使用promises,这是ECMAScript 6 标准的JavaScript 功能。如果您的目标平台不支持promises,请使用PromiseJs 填充它。

Promises 是一种处理 JavaScript 中异步操作的新方法(而且更好):

$('a.button').click(function(){
    if (condition == 'true'){
        function1(someVariable).then(function() {
            //this function is executed after function1
            function2(someOtherVariable);
        });
    }
    else {
        doThis(someVariable);
    }
});


function function1(param, callback) {
    return new Promise(function (fulfill, reject){
        //do stuff
        fulfill(result); //if the action succeeded
        reject(error); //if the action did not succeed
    });
} 

对于这个简单的示例,这似乎是一个很大的开销,但对于更复杂的代码,它比使用回调要好得多。您可以使用多个 then 语句轻松链接多个异步调用:

function1(someVariable).then(function() {
    function2(someOtherVariable);
}).then(function() {
    function3();
});

您还可以轻松包装 jQuery deferrds(从 $.ajax 调用返回):

Promise.resolve($.ajax(...params...)).then(function(result) {
    //whatever you want to do after the request
});

正如@charlietfl 所说,$.ajax() 返回的jqXHR 对象实现了Promise 接口。所以其实没必要用Promise包起来,直接用就可以了:

$.ajax(...params...).then(function(result) {
    //whatever you want to do after the request
});

【讨论】:

  • Promise.resolve 包装 $.ajax 是反模式,因为 $.ajax 返回可承诺的承诺
  • @charlietfl 但它不是实际的Promise,它只是实现了接口。我不确定将真正的Promise 传递给它的then 方法时它的行为如何,或者如果将jqXHRPromise 传递给它,Promise.all 会做什么。为此,我需要做进一步的测试。不过谢谢你的提示,我会把它添加到答案中!
  • 实际上在 jQuery 版本 3+ 中是 Promises A+ 兼容的。不管$.ajax.then不是新人
【解决方案5】:

或者您可以在一个功能完成时触发自定义事件,然后将其绑定到文档:

function a() {
    // first function code here
    $(document).trigger('function_a_complete');
}

function b() {
    // second function code here
}

$(document).bind('function_a_complete', b);

使用这种方法,函数'b'只能在函数'a'之后执行,因为触发器只有在函数a执行完成时才存在。

【讨论】:

  • “从 jQuery 1.7 开始,.on() 方法是将事件处理程序附加到文档的首选方法。” api.jquery.com/bind
【解决方案6】:

你可以这样做

$.when(funtion1()).then(function(){
    funtion2();
})

【讨论】:

    【解决方案7】:

    这取决于 function1 正在做什么。

    如果 function1 正在执行一些简单的同步 javascript,例如更新 div 值或其他内容,则 function2 将在 function1 完成后触发。

    如果 function1 正在进行异步调用,例如 AJAX 调用,则需要创建“回调”方法(大多数 ajax API 都有回调函数参数)。然后在回调中调用function2。例如:

    function1()
    {
      new AjaxCall(ajaxOptions, MyCallback);
    }
    
    function MyCallback(result)
    {
      function2(result);
    }
    

    【讨论】:

      【解决方案8】:

      如果方法 1 必须在方法 2、3、4 之后执行。下面的代码 sn-p 可以是在 JavaScript 中使用 Deferred 对象的解决方案。

      function method1(){
        var dfd = new $.Deferred();
           setTimeout(function(){
           console.log("Inside Method - 1"); 
           method2(dfd);	 
          }, 5000);
        return dfd.promise();
      }
      
      function method2(dfd){
        setTimeout(function(){
         console.log("Inside Method - 2"); 
         method3(dfd);	
        }, 3000);
      }
      
      function method3(dfd){
        setTimeout(function(){
         console.log("Inside Method - 3"); 	
         dfd.resolve();
        }, 3000);
      }
      
      function method4(){   
         console.log("Inside Method - 4"); 	
      }
      
      var call = method1();
      
      $.when(call).then(function(cb){
        method4();
      });
      <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

      【讨论】:

        【解决方案9】:

        如果 function1 是某个同步函数,您想将其转换为异步函数,因为它需要一些时间才能完成,并且您无法控制它来添加回调:

        function function1 (someVariable) {
            var date = Date.now ();
            while (Date.now () - date < 2000);      // function1 takes some time to complete
            console.log (someVariable);
        }
        function function2 (someVariable) {
            console.log (someVariable);
        }
        function onClick () {
            window.setTimeout (() => { function1 ("This is function1"); }, 0);
            window.setTimeout (() => { function2 ("This is function2"); }, 0);
            console.log ("Click handled");  // To show that the function will return before both functions are executed
        }
        onClick ();
        

        输出将是:

        Click handled
        

        ...2 秒后:

        This is function 1
        This is function 2
        

        之所以可行,是因为调用 window.setTimeout() 会在 JS runtine 任务循环中添加一个任务,这是异步调用所做的,并且因为 JS 运行时“run-to-completion”的基本原则确保了onClick() 在结束之前永远不会被中断。

        请注意,这很有趣,因为它使代码难以理解......

        【讨论】:

          猜你喜欢
          • 2021-07-25
          • 1970-01-01
          • 1970-01-01
          • 2018-07-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-02-24
          相关资源
          最近更新 更多