Notify after async task is done

2019-03-06 10:29发布

I'm building a game with move.js for animation, but it takes too long so when the player click on the right solution it displays the winning message before the right solution change it's color, so I used deferred object to fire an event and catch it when the animation ends.

Here's my code:

var deferred = new $.Deferred();
click(e);
//show message when game is over
$.when(deferred).then(function(){
    if (this.checkIfWin()){
        alert('you won !');
        this.nextLevel();
    }
});
function click(e){
    move(e)
    .set('background-color','black')
    .delay('0.1s')
    .end();
    deferred.notify();
}

but it's not notified and the message doesn't show up.What am I missing here ?

2条回答
聊天终结者
2楼-- · 2019-03-06 10:35

Because animations in javascript are asynchronous (they run via timers), the only way to know when they are done is to hook into some sort of completion callback or completion notification.

I don't know move.js myself, but it looks like you can get such a callback by supplying a callback to the .end(fn) method. But, you will also have to fix your code because this in this.checkIfWin() will not be the right value in either of these code blocks. I don't know what you want it to be (since you don't show that part of your code), but you will have to refer to some other object besides this. In any case, here's the general structure of the code both with and without the use of a deferred.

var deferred = new $.Deferred();

// your code was using this here 
// so I will save a reference to it that can be used later, but there is
// probably a better way to do this if I could see the rest of your code
var obj = this;

click(e);

//show message when game is over
deferred.promise().then(function(){
    if (obj.checkIfWin()){
        alert('you won !');
        obj.nextLevel();
    }
});

function click(e){
    move(e)
    .set('background-color','black')
    .delay('0.1s')
    .end(function() {
        deferred.resolve();
    });
}

In this case, it doesn't look like you really need to use the deferred as you could just put the completion code right in the callback:

// your code was using this here 
// so I will save a reference to it that can be used later, but there is
// probably a better way to do this if I could see the rest of your code
var obj = this;

click(e);

function click(e){
    move(e)
    .set('background-color','black')
    .delay('0.1s')
    .end(function() {
        if (obj.checkIfWin()){
            alert('you won !');
            obj.nextLevel();
        }
    });
}
查看更多
欢心
3楼-- · 2019-03-06 10:37

Edit, Added callback function to .end() to include deferred.notify . See comments , Move#end([fn])

Try

var deferred = new $.Deferred();
click(e); // `e` undefined ?
deferred.progress(function(msg) {
// `this` within `deferred`
// references `deferred` object ,
// try `obj.checkWin()`, `obj.nextLevel()`
  if (obj.checkWin()) {
    alert(msg);
    obj.nextLevel();
  }
});

function click(e) {
    // `e` undefined ?
    move(e)
    .set('background-color','black')
    // `.delay()` accepts `number` as argument ? 
    .delay('0.1s')
      // see comments , 
      // http://visionmedia.github.io/move.js/#example-11
    .end(function() {
      deferred.notify("you won !");
    });
};

jsfiddle http://jsfiddle.net/guest271314/4Av4Z/

查看更多
登录 后发表回答