【问题标题】:Notify after async task is done异步任务完成后通知
【发布时间】:2014-07-26 13:47:56
【问题描述】:

我正在使用move.js 构建一个用于动画的游戏,但是它花费的时间太长,所以当玩家点击正确的解决方案时,它会在正确的解决方案改变它的颜色之前显示获胜消息,所以我使用延迟对象来触发一个事件并在动画结束时捕获它。

这是我的代码:

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();
}

但它没有收到通知,消息也没有出现。我在这里错过了什么?

【问题讨论】:

    标签: javascript jquery jquery-deferred


    【解决方案1】:

    因为 javascript 中的动画是异步的(它们通过计时器运行),所以知道它们何时完成的唯一方法是挂钩某种完成回调或完成通知。

    我自己并不了解 move.js,但看起来您可以通过向 .end(fn) 方法提供回调来获得这样的回调。但是,您还必须修复您的代码,因为this.checkIfWin() 中的this 在这两个代码块中都不是正确的值。我不知道你想要它是什么(因为你没有显示你的代码的那部分),但你必须引用除this 之外的其他对象。在任何情况下,以下是使用和不使用延迟的代码的一般结构。

    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();
        });
    }
    

    在这种情况下,您似乎不需要使用 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);
    
    function click(e){
        move(e)
        .set('background-color','black')
        .delay('0.1s')
        .end(function() {
            if (obj.checkIfWin()){
                alert('you won !');
                obj.nextLevel();
            }
        });
    }
    

    【讨论】:

    • 为什么投反对票?这就是你知道 move.js 动画何时完成的方式。
    • -1 。不适用于与deferred.notify 相关的问题;该用户使用的类似模式。问题不要求 deferred.promise() 回调。谢谢
    • this.then() 回调中,在顶部示例中,将引用deferred 对象本身,除非强制转换为其他对象?谢谢
    • @guest271314 - 问题是如何知道动画何时完成。这是这里唯一真正回答这个问题的答案。该动作可以在有或没有承诺的情况下触发。我没有使用.notify(),因为承诺标准正在删除该功能,因此通常不建议使用它进行编码。我用另外两种方式解决了这个问题。如果 OP 真的想使用 .notify,那么仍然可以使用此方案。
    • @guest271314 - 是的,我知道this 的问题。这就是为什么我在我的帖子中解释说 OP 必须在那里使用对其他对象的引用。他们没有展示足够多的代码让我确切地知道如何推荐它。我的代码完全注释了这种效果。
    【解决方案2】:

    编辑,向.end() 添加回调函数以包括deferred.notify。见 cmets,Move#end([fn])

    试试

    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/

    【讨论】:

    • 这行不通,因为您在动画完成之前通知了进度事件。
    • @jfriend00 如果可能,请在帖子中指出在动画完成之前触发进度事件的帖子中的行?谢谢
    • javascript 中的动画是异步的。
    • @jfriend00 如果可能的话,能否请在动画完成之前在帖子中指出进度事件被触发的地方?谢谢
    • 动画等异步操作在未来某个时间完成(它们由计时器或原生 CSS 过渡/动画运行)。知道何时完成的唯一方法是使用某种完成通知。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-10
    • 1970-01-01
    • 2023-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多