Run function after another one completes

2019-01-23 20:59发布

问题:

function1 = function(){

  something.on('transitionend', function(){
    // now function2 should run
  });

}

function2 = function(){
  alert('ok');
}

function1();
function2();

So I heard about jQuery promises. I would return a "deferred" object, and inside the event handler I would call deferred.resolve();

But what happens if i have multiple event handlers there and I only want the next function to run when all have been fired? + I don't like the idea of introducing something foreign like "deferred" into other parts of the code.

Is there any other way to detect if function1 has finished all its work?

回答1:

Try this,

 $.when($.ajax(fuction1())).then(function () {

    fuction2;

});

Here fuction1 is your first function to call, and fuction2 is your second function.



回答2:

Either you take the promise approach, or you take the callback approach.

With callbacks, you'd pass function2 as a parameter to function1;

function1 = function(callback){

  something.on('transitionend', function(){
      callback();
  });

}

function2 = function(){
  alert('ok');
}

function1(function2);

... but then you get nested-hell if you have function3 dependant on function2, and function4 dependant on 3.

This is why you'd go down the deferred route;

function1 = function(){
  var def = new jQuery.Deferred();

  something.on('transitionend', function(){
      def.resolve(arguments);
  });

  return def.promise();
}

function2 = function(){
  alert('ok');
}

function1().done(function2);

... which would allow you to chain successive functions rather than nesting them (providing they all returned promises, of course).

Combining event handlers and deferreds is a bit messy. So if you went down the route of having multiple event handlers, you'd end up having to do something lame such as;

function1 = function(){
  var def = new jQuery.Deferred();
  var wait = 4;

  function maybeFire() {
      if (--wait) {
          def.resolve();
      }
  }

  something.on('transitionend', maybeFire);
  something.on('somethingelse', maybeFire);
  something.on('somethingelse', maybeFire);
  something.on('somethingelse', maybeFire);

  return def.promise();
}

function2 = function(){
  alert('ok');
}

function1().done(function2);

The real way of combining multiple deferreds is by using $.when(), but unfortunately here you don't have multiple deferreds, and adding them will be as messy as using the maybeFire approach.



回答3:

Note, transitionend event may fire multiple times if all is set within css transition property value

Try (this pattern)

i.e.g.,

html

<button>click</button>

css

button {
    width: 100px;
    -webkit-transition: width 1s;
}
.transition {
    width: 150px
}

js

$(function() {
    // `$.Callbacks("once")` to fire `alert` once ,
    // even if `all` set within `css` `transition` 
    // property value
    var callbacks = $.Callbacks(); 

    function2 = function(j) {
      alert(j);
    };

    callbacks.add(function2);

    $(window).on("transitionComplete", function(e, i) {
     // function2(i);
        callbacks.fireWith($(this), [i]);
    });
    // `webkitTransitionEnd transitionend msTransitionEnd oTransitionEnd`
    function1 = function() {
      $("button").on('transitionend', function (e) {
        $(window).trigger("transitionComplete", ["ok"]);
      });
    };

    function1();

    $("button").on("click", function(e) {
      $(this).toggleClass("transition");
    });

});

jsfiddle http://jsfiddle.net/guest271314/u7B9K/