【问题标题】:Dynamically adding sequential actions using deferreds使用延迟动态添加顺序操作
【发布时间】:2015-11-04 08:48:16
【问题描述】:

这是我当前的代码:https://gist.github.com/benjamw/f6d5d682caddd4c1e506

我要做的是:根据用户点击页面时的 URL,从服务器拉取不同的数据,当这一切都完成后,使用 Hogan 呈现页面。

我的问题是步骤 B 需要来自步骤 C 的数据才能正确呈现,步骤 C 需要来自步骤 B 的数据来提取正确的数据,但是如果这是用户请求的页面(数据C 需要正确拉取是直接转到 C 时 URL 的一部分。

我有一个 Deferred 存储在 Thing 中,它在各种拉动步骤中得到解决并触发渲染,但在 pull_B 中,我不希望它在从两个 @ 获取并清除数据之前解决987654325@ 和pull_C。但是如果用户直接通过 C,那么我希望它能够很好地解决。

当进程通过B路径包含C路径时,如何在init()函数中动态添加一个promise到when

或者,我怎样才能让 B 将它的承诺传递给 C,然后在那里解决它,但仍然保持能够通过 C 本身的功能,并且让它仍然在不先通过 B 的情况下解决主要的延迟对象?

我正在努力不为此陷入回调地狱,但我发现这样做很难。

【问题讨论】:

  • 代码确实应该在问题中,而不是链接。
  • 我听过很多次,如果代码很长,把它放在别处并链接到它。如果这段代码更短,我肯定会把它放在问题中。

标签: javascript jquery deferred .when


【解决方案1】:

问题的症结显然在于 B 和 C 之间的关系,总结起来似乎是:

  • 如果是B,pull-C().then(pull-B);
  • 如果是C,pull-B().then(pull-C);

在当前的尝试中,您尝试在pull-B()pull-C() 中编写流程逻辑时遇到了问题,这最终是可能的,但很复杂。

一个更简单的策略是使pull_X() 函数非常简单——返回承诺的数据检索器,并在.init() 中的switch/case 结构内编写流逻辑和数据清理。您将在下面的代码中看到我的意思。

除了更简单之外,这还将避免pull_B()pull_C() 之间的任何循环依赖。

通过充分利用 Promise,您还会发现:

  • 不再需要this.dfd(支持从函数返回承诺)。
  • this.data 的需求消失了(赞成允许承诺传递数据)。
  • 不再需要将回调传递给.pull()(有利于在调用者中链接.then())。因此,回调地狱消失了。

试试这个:

(function($) {
    "use strict";
    /**
     * The Thing
     *
     * @constructor
     */
    function Thing( ) {
        /* properties */ 
        this.url = [
            /* path */,
            /* id */
        ];
    }
    Thing.prototype.pull = function(url, args, type) {
        return $.ajax({
            type: type || 'GET',
            url: foo.root + url,
            data: $.extend({}, args || {}),
            dataType: 'json'
        });
    };
    Thing.prototype.pull_As = function() {
        return this.pull('a', this.query);
    };
    Thing.prototype.pull_A = function() {
        this.nav = false;
        return this.pull('a/'+ this.url[2]);
    };
    Thing.prototype.pull_B = function() {
        return this.pull('b/' + this.url[2]);
    };
    Thing.prototype.pull_C = function(id) {
        return this.pull('c/' + id || this.url[2]);
    };
    Thing.prototype.pull_D = function() {
        return this.pull_As();
    };
    Thing.prototype.render = function(data) {
        var i, len, html,
            that = foo.thing, /* because 'this' is the promise object */
            title = document.title.split('|');
        for (i = 0, len = title.length; i < len; i += 1) {
            title[i] = $.trim(title[i]);
        }
        title[0] = $.trim(that.title);
        document.title = title.join(' | ');
        html = Hogan.wrapper.render({
            'data': data,
        });
        $('#thing_wrapper').empty().append(html);
    };
    Thing.prototype.init = function( ) {
        var promise,
            that = this;
        switch (this.url[1].toLowerCase( )) {
            case 'a':
                promise = this.pull_A().then(function(data_A) {
                    /* ... do A data cleanup */ 
                    return data_A;//will be passed through to .render()
                });
                break;
            case 'b':
                promise = this.pull_C().then(function(data_C) {
                    //Here an inner promise chain is formed, allowing data_C, as well as data_B, to be accessed by the innermost function.
                    return that.pull_B().then(function(data_B) {
                        var data = ...;//some merge of data_B and data_C
                        return data;//will be passed through to .render()
                    });
                });
                break;
            case 'c':
                var id = ???;
                promise = this.pull_C(id).then(function(data_C) {
                    /* ... do C data cleanup */ 
                    return data_C;//will be passed through to .render()
                });
                break;
            case '':
            default:
                promise = this.pull_D().then(function(data_D) {
                    /* ... do D data cleanup */ 
                    return data_D;//will be passed through to .render()
                });
        }
        promise.then(this.render, console.error.bind(console));
    };
    window.Thing = Thing;
})(jQuery);

请特别注意,各种函数会返回一个承诺或数据。

我怀疑我的尝试是否 100% 正确。整体结构应该没问题,但您需要仔细查看细节。我可能误解了 B/C 依赖项。运气好的话,它会比我编写的代码更简单。

编辑:根据下面的 cmets 修改代码。

【讨论】:

  • 在pull_B函数中,它依赖于pull_C的数据,但不是互惠的。 pull_C 不依赖 pull_B 中的数据,可以自行调用。这是我的主要问题,但是使用您的方法来提取除 ajax 调用之外的所有内容并返回承诺,它可能会对我有所帮助。谢谢。
  • then 函数内部存在一些this 问题。在这些函数中,this 指的是 promise 对象。我相信你知道,但为了后代,我在这里注明。
  • 我对@9​​87654337@ 案件有疑问。当data通过pull_B之后再传给pull_C,就是pull_B的响应。一旦进入pull_C,如果pull_B 的返回值也是一个promise 对象,我应该如何将pull_C 的响应数据与pull_B 返回的数据合并?我知道我可以在这些功能之外做到这一点,我只是想知道我是否遗漏了一些技巧。
  • 除了这些问题和一些小的调整之外,这非常有效!谢谢!
  • 我很困惑。从第一条评论开始-“pull_B 依赖于 pull_C 的数据”,但“pull_C 不依赖于 pull_B 的数据”。来自第 3 条评论 - “当通过 pull_B 后将数据传递到 pull_C ...”。哪种情况简单,哪种情况复杂?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多