级联jQuery.Deferred

时间:2016-12-07 17:19:03

标签: javascript jquery jquery-deferred

NOT AN" ANTIPATERN" :这不常见"反模式"简单地通过直接返回嵌套的Deferred对象就可以解决这个摘录...这个摘录是嵌套的延迟加载代码的大量简化,它将在不久的将来返回Deferred,因此不可能直接从原始方法返回尚未存在的Deferred。

除此之外,从原始(顶级)方法返回的延迟取决于在不久的将来创建的多个延迟,其中只有"拒绝"马上回来......

我发现自己最近经常写这样的事情:

My.prototype.init=function() {
    var $dfd = $.Deferred();

    this.initSomethingElse() // returns Deferred
        .done(function() {
            $dfd.resolve();
        })
        .fail(function() {
            $dfd.reject();
        });

    return $dfd;
}

我写了一个简短的函数,在Deferred上添加.link()方法,简化如下:

My.prototype.init=function() {
    var $dfd = $.Deferred();

    this.initSomethingElse() // returns $.Deferred(addLinkMethodFce)
        .link($dfd);

    return $dfd;
}

但我认为它可能太普遍了,所以其他人可能会想到它而我可能错过了jQuery中的一些开箱即用的解决方案。

问题:jQuery是否可以链接现有Deferred对象与其他Deferred对象的方式,如果链接对象被解析/拒绝当前Deferred将以相同方式解析/拒绝?

dfd1Promise = $.when(dfd2)之类的东西,除了不需要创建新的Promise而只需简单地#34;链接"将现有对象放在一起而不创建新对象dfd1.link(dfd2)

感谢。

编辑#1:我看到许多问题的答案我还没有问过 - 比如"我应该使用延期吗?"我想澄清一下情况。

我正在使用异步加载的代码(My.prototype.init会加载异步脚本和数据,使其返回延迟到调用者)。

该代码还依赖于异步第三方代码 - 我无法修改的API - initSomethingElse()也将在不久的将来解决,并返回Deferred。

重点是,如果该代码被拒绝,我的代码必须被拒绝。而且我希望有一些神奇的标准糖语法可以重复$theirDfd.reject(function() {$myDfd.reject.call(...);});

只是有一种标准方式来执行$myDfd.link($theirDfd);

我只是简单地简化了这种情况,以便在几行上表达出来,所以不要误以为我可能不需要延期或其他任何我没有问过的......

编辑#2:为了进一步澄清.link()的作用,这里是我目前使用的帮助代码:

/**
 * Adds some syntax sugar methods to Deferred object.
 *
 *   Deferred.link(dfd, ...) - if this object resolves/rejects/progresses it will resolve/reject/progress linked object as well
 *   Deferred.linkResolve(dfd, ...) - if this object resolves it will resolve linked object as well
 *   Deferred.linkReject(dfd, ...) - if this object rejects it will reject linked object as well
 *   Deferred.linkProgress(dfd, ...) - if this object progresss it will progress linked object as well
 *
 * Methods can be appended to Deferred object by two ways:
 *
 * $dfd = edfd($.Deferred());
 * $dfd = $.Deferred(edfd);
 *
 * @access public
 * @return {Deferred}
 */
function edfd($dfd) {

    /**
     * Helper used by this.link(), this.linkReject(), this.linkProgress(), this.linkResolve()
     *
     * @access private
     * @param {Boolean} accept link this Deferred's accept call to target's accept
     * @param {Boolean} reject link this Deferred's reject call to target's reject
     * @param {Boolean} progress link this Deferred's progress call to target's progress
     * @param {Object} targets array of Deferreds or array of arrays of Deferreds
     * @return {Deferred} this (called in $dfd context)
     */
    function linker(accept, reject, progress, targets) {
        targets = dna.core.getOpts(targets, [['dfdList', 'object'], 'recursive']);

        for (var i = 0; i < targets.dfdList.length; i++) {
            var $link = targets.dfdList[i];
            $dfd.then(
                accept && function() {$link.resolve.apply($link, arguments);},
                reject && function() {$link.reject.apply($link, arguments);},
                progress && function() {$link.progress.apply($link, arguments);}
            );
        }

        return this;
    }

    /**
     * If link this Deferred's rejection/resolution/progress to all linked Deferreds.
     *
     * @access public
     * @param {...Deferred} dfd jQuery Deferred objects or arrays of Deferred objects.
     * @return {Deferred} this object
     */
    $dfd.link = function() {
        return linker(true, true, true, arguments);
    };

    /**
     * If this Deferred is resolved then resolve also linked Deferreds.
     *
     * @access public
     * @param {...Deferred} dfd jQuery Deferred objects or arrays of Deferred objects.
     * @return {Deferred} this object
     */
    $dfd.linkResolve = function() {
        return linker(true, false, false, arguments);
    };

    /**
     * If this Deferred gets rejected then reject also linked Deferreds.
     *
     * @access public
     * @param {...Deferred} dfd jQuery Deferred objects or arrays of Deferred objects.
     * @return {Deferred} this object
     */
    $dfd.linkReject = function() {
        return linker(false, true, false, arguments);
    };

    /**
     * If this Deferred progresses then progress also linked Deferreds.
     *
     * @access public
     * @param {...Deferred} dfd jQuery Deferred objects or arrays of Deferred objects.
     * @return {Deferred} this object
     */
    $dfd.linkProgress = function() {
        return linker(false, false, true, arguments);
    };

    return $dfd;
}

编辑#3:仅适合那些渴望特殊用途的人。延迟对象的初始化与此this.$dfd = $.Deferred(edfd);一样初始化(请参阅我上面针对此问题的解决方案 - function edfd(...)

/**
 * Public interface as required for payment processors.
 *
 * @access public
 * @param {Object} payData
 * @return {Deferred} resolved/rejected based on payment result.
 */
Braintree.prototype.process = function(payData) {
    this.cleanUp();
    this.payData = payData;
    this.createLayer();
    this.initBraintree(payData.clientToken)
        .linkReject(this.$dfd);

    return this.$dfd;
};

1 个答案:

答案 0 :(得分:-1)

<强> TL; DR

  

问题:jQuery是否可以链接现有Deferred对象与其他Deferred对象的方式,如果链接对象被解析/拒绝当前Deferred将以相同方式解析/拒绝?

我看到你在想什么以及为什么;然而,ES2015已经通过Promise链接为您解决了这个问题。很好的例子:Promise.all()MDN link)是这类功能的一个很酷的实现(参见:&#34;快速失败&#34;)。

如果您需要,请使用多个延期&#34;链接&#34;他们一起使用jQuery.when()

var d1 = $.Deferred();
var d2 = $.Deferred();

$.when( d1, d2 ).done(function ( v1, v2 ) {
    console.log( v1 ); // "Fish"
    console.log( v2 ); // "Pizza"
});

d1.resolve( "Fish" );
d2.resolve( "Pizza" );

(代码来源:https://api.jquery.com/jquery.when/

在SO上阅读此good answer关于您的问题(及其相关链接)。可能不会立即明白为什么答案有助于你的案例,但要考虑并编写一些示例代码,你就能更好地理解。

正如其他人所暗示的那样:

  • 您希望避免 deferred,如果可能的话
  • 使用.then()(最后.catch()
  • 链接您的承诺