2012-08-10 41 views
3

我正在學習如何使用jQuery的deferred,並且我注意到使用$.when以及.notifyWith的問題。

我做出了表率,而無需使用$.when.notifyWith作品完美

function a() { 
    var d = new $.Deferred, 
     $A = $('#A'), 
     $P = $('#P').progressbar(); 

    setTimeout(function() { 
     $A.css('background-color', 'blue'); 
     d.notifyWith($P, [.5]); 
    }, 2000); 

    setTimeout(function() { 
     $A.text('test'); 
     d.notifyWith($P, [1]); 
     d.resolveWith($P, ['done']); 
    }, 4000); 

    return d.promise(); 
} 
$('#G').click(function() { 
    a().progress(function(x) { 
     this.progressbar({ 
      value: x * 100 
     }); 
    }).done(function(x) { 
     alert(x) 
    }); 
});​ 

DEMO:http://jsfiddle.net/NTICompass/3DDSa/3/

裏面.progressthis設置爲$P,所以進度正常移動。

我想分裂2和setTimeout行動統一到單獨的函數,所以我這樣做,並用$.when的承諾合併爲一個:

(function() { 
    var $P = $('#P').progressbar(); 
    window.a = function() { 
     var d = new $.Deferred, 
      $A = $('#A'); 

     setTimeout(function() { 
      $A.css('background-color', 'blue'); 
      d.notifyWith($P, [.5]); 
      d.resolve('a()'); 
     }, 2000); 

     return d.promise(); 
    } 

    window.b = function() { 
     var d = new $.Deferred, 
      $A = $('#A'); 

     setTimeout(function() { 
      $A.text('test'); 
      d.notifyWith($P, [.5]); 
      d.resolve('b()'); 
     }, 4000); 

     return d.promise(); 
    } 
}()) 

$('#G').click(function() { 
    $.when(a(), b()).progress(function(x, y) { 
     this.progressbar({ 
      value: ((x || 0) + (y || 0)) * 100 
     }); 
    }).done(function(x, y) { 
     alert(x + ' ' + y) 
    }); 
});​ 

DEMO:http://jsfiddle.net/NTICompass/3DDSa/16/

出於某種原因this.progress不是$P。相反,它是延遲對象(或承諾對象,我不太確定)。爲什麼不是this等於$P

+0

1.7.2的第1336行http://code.jquery.com/jquery-1.7.2.js將作爲上下文傳遞承諾,供參考。 – 2012-08-10 19:36:56

+0

@KevinB:那麼,這可能是(全能的)jQuery中的一個錯誤? – 2012-08-10 19:42:24

+0

Docs do say:'deferred.notifyWith(context [,args])'「上下文作爲'this'對象傳遞給progressCallbacks。」可能是一個錯誤? – 2012-08-10 19:43:52

回答

2

這已在jQuery 1.8.0中修復,其中this實際上是一組上下文。

$('#G').click(function() { 
    var index = 0; 
    $.when(a(), b()).progress(function(x, y) { 
     this[index++].progressbar({ 
      value: ((x || 0) + (y || 0)) * 100 
     }); 
    }).done(function(x, y) { 
     alert(x + ' ' + y) 
    }); 
});​ 

DEMO:http://jsfiddle.net/3D4wq/1/(感謝jaubourg從jQuery bug跟蹤系統)

注:這裏面.progress(和.done),arguments.length總是會傳遞給$.when元素的數量,所以this[arguments.length-1]韓元」 t(總是)工作。

第一次.progress被稱爲arguments[.5, undefined]

2

我不確定是否有理由將其寫入,但只需將第1336行的promise更改爲this即可使代碼正常運行。

http://jsfiddle.net/3DDSa/18/

$.when = function(firstParam) { 
    var args = [].slice.call(arguments, 0), 
     i = 0, 
     length = args.length, 
     pValues = new Array(length), 
     count = length, 
     pCount = length, 
     deferred = length <= 1 && firstParam && jQuery.isFunction(firstParam.promise) ? firstParam : jQuery.Deferred(), 
     promise = deferred.promise(); 

    function resolveFunc(i) { 
     return function(value) { 
      args[i] = arguments.length > 1 ? [].slice.call(arguments, 0) : value; 
      if (!(--count)) { 
       deferred.resolveWith(deferred, args); 
      } 
     }; 
    } 

    function progressFunc(i) { 
     return function(value) { 
      pValues[i] = arguments.length > 1 ? [].slice.call(arguments, 0) : value; 
      deferred.notifyWith(this, pValues); // this is line 1336 
     }; 
    } 
    if (length > 1) { 
     for (; i < length; i++) { 
      if (args[i] && args[i].promise && jQuery.isFunction(args[i].promise)) { 
       args[i].promise().then(resolveFunc(i), deferred.reject, progressFunc(i)); 
      } else { 
       --count; 
      } 
     } 
     if (!count) { 
      deferred.resolveWith(deferred, args); 
     } 
    } else if (deferred !== firstParam) { 
     deferred.resolveWith(deferred, length ? [firstParam] : []); 
    } 
    return promise; 
};​ 

可能是值得加入的車票。

+0

您想將此添加爲[ticket](http://bugs.jquery.com/ticket/12253)的評論嗎?還是應該? – 2012-08-10 19:59:41

+0

看起來像'resolveWith'似乎有同樣的問題'deferred.resolveWith(deferred,args);':-P – 2012-08-10 20:06:25

+0

是的,在幾個地方。 – 2012-08-10 20:07:05