使用promises重写代码

时间:2014-06-30 11:05:36

标签: javascript jquery angularjs timeout promise

我有以下代码导致两次调用Webtrends被取消(即这两个调用在浏览器时没有给出http 200但是在浏览器的网络选项卡中有一条被取消的消息)

mercury.Tracking.logUsage("export", GetSelectedExportType(form));
mercury.Tracking.logUsage('exportchart', mercury.ChartContainer.currentChartUri(), path);
form[0].submit();

我以这种方式重写了这一点以避免这个问题,因为在我看来,之所以取消对Webtrends的调用是因为表单提交是这样的,所以在调用表单上的提交之前我等了两秒钟

mercury.Tracking.logUsage("export", GetSelectedExportType(form));
mercury.Tracking.logUsage('exportchart', mercury.ChartContainer.currentChartUri(), path);

var submit = function () {
  setTimeout(function() {
    form[0].submit();
  }, 2000);
};
submit();

问题是,有更好的方法,使用承诺或回调或其他任何方法吗?

logUsage代码是

(function ($, window) {
    function Tracking() {

    }

    Tracking.prototype.chartTitle = function () {
        return $('#chartNameInfo').text();
    };

    Tracking.prototype.hostName = function () {
        return $('#trackingVars').data('host-name');
    };

    Tracking.prototype.page = function () {
        return $('#trackingVars').data('page');
    };

    Tracking.prototype.currentUser = function () {
        return window.config.userId;
    };

    Tracking.prototype.logUsage = function (action, resourceUri, actionTargetUri, additionalTags) {
        // action: action performed - e.g. create, delete, export
        // resourceUri:  URI of API resource *on* which action is being performed (required), e.g. /users/current/annotations/{annotation-id}
        // actionTargetUri: URI of API resource *to* which action is being performed (optional), e.g. /charts/{chart-id}

        if (action.indexOf("DCSext.") < 0) {
            action = "DCSext." + action;
        }

        var jsonString = '{"' + action + '"' + ':"1"}';
        var jsonObj = JSON.parse(jsonString);

        if (additionalTags == null) {
            additionalTags = jsonObj;
        }
        else {
            additionalTags = $.extend({}, additionalTags, jsonObj); //Append two JSON objects
        }

        var trackingargs = $.extend({
            'DCSext.resource-uri': resourceUri,
            'DCSext.action-target-uri': actionTargetUri,
            'WT.ti': this.chartTitle(),
            'DCSext.dcssip': this.hostName(),
            'DCSext.em-user-id': this.currentUser(),
            dsci_uri: this.page()
        }, additionalTags);
        try {
            WebTrends.multiTrack({ args: trackingargs });
        } catch (e) {
            console.log(e);
        }
    };

    window.Tracking = new Tracking();

    $(function() {
        $('body').on('click', 'a[data-tracking-action]', function() {
            window.Tracking.logUsage($(this).data('tracking-action'), $(this).data('tracking-resource'));
        });

        $(document).on('attempted-access-to-restricted-resource', function(event, href) {
            window.Tracking.logUsage('unauthorisedResourceAccessUpsell', href.url);
        });
    });

})(jQuery, window);

2 个答案:

答案 0 :(得分:3)

如果提供了额外的信息,我想我现在可以回答你的问题了。

WebTrends doc,您可以为WebTrends.MultiTrack调用添加完成回调。 你能做什么:

Tracking.prototype.logUsage = function (action, resourceUri, actionTargetUri, additionalTags) {
  ...
  var finished = $.Deferred();
  ...
  try {
    WebTrends.multiTrack({ args: trackingargs, finish: function(){finished.resolve();}});
  }
  ...
  return finished;
}

然后在你的代码中:

$.when(mercury.Tracking.logUsage("export", GetSelectedExportType(form)),
mercury.Tracking.logUsage('exportchart', mercury.ChartContainer.currentChartUri(), path))
  .done(function(){
    form[0].submit(); 
  });

我没有对此进行测试,但我认为它应该可行。希望它有所帮助。

说明:

jQuery.when()

  

描述:提供一种基于one执行回调函数的方法   或更多对象,通常是表示异步的延迟对象   事件

基本上,jQuery.when()将接受一个或多个延迟(构建承诺)或承诺,并将返回一个在它们全部满足时履行的承诺。从那里,我们可以选择使用.done().then()方法将处理程序添加到我们的承诺中,该承诺将被调用一次或承诺完成。 (promise表示异步操作的结果)。

因此,在上面的代码中,我在您的logUsage方法中创建了一个新的延迟对象,并且该方法返回延迟,因此您可以将这些延迟传递给jQuery.when方法,何时它们将是实现(这就是我在WebTrends.Multitrack调用中添加完成回调的原因),传递给deferred.done()的处理程序将被执行。

我希望这不会太混乱,我不确定我是否正确解释它。

答案 1 :(得分:2)

不想偷走Antoine的代表。他的回答基本上很好,但...部分可以比问题更有效地加以充实,还有一些其他要考虑的要点。

Tracking.prototype.logUsage = function (action, resourceUri, actionTargetUri, additionalTags) {
    // action: action performed - e.g. create, delete, export
    // resourceUri:  URI of API resource *on* which action is being performed (required), e.g. /users/current/annotations/{annotation-id}
    // actionTargetUri: URI of API resource *to* which action is being performed (optional), e.g. /charts/{chart-id}

    try { 
        // you might as well wrap all the preamble in the try{}, just in case it it error-prone

        if (action.indexOf("DCSext.") < 0) {
            action = "DCSext." + action;
        }

        //trackingargs can be defined efficiently as follows, avoiding the need for the variable `jsonObj` and the ugly JSON.parse().
        var trackingargs = $.extend({
            'DCSext.resource-uri': resourceUri,
            'DCSext.action-target-uri': actionTargetUri,
            'WT.ti': this.chartTitle(),
            'DCSext.dcssip': this.hostName(),
            'DCSext.em-user-id': this.currentUser(),
            'dsci_uri': this.page()
        }, additionalTags || {}); // `additionalTags || {}` caters for missing or null additionalTags

        trackingargs[action] = 1;//associative syntax gets around the limitation of object literals (and avoids the need for JSON.parse()!!!).

        //to keep things tidy, return $.Deferred(fn).promise()
        return $.Deferred(function(dfrd) {
            WebTrends.multiTrack({
                args: trackingargs,
                finish: dfrd.resolve //no need for another function wrapper. `$.Deferred().resolve` and `$.Deferred().reject` are "detachable"
            });
        }).promise();//be sure to return a promise, not the entire Deferred.

    } catch (e) {

        console.log(e);

        //Now, you should really ensure that a rejected promise is always returned.
        return $.Deferred.reject(e).promise();//Surrogate re-throw.

    }
};

查看代码中的评论

由于Tracking.prototype.logUsage现在可以返回被拒绝的承诺,并且您可能不希望.logUsage()无法阻止您的表单提交,您可能希望将已拒绝的承诺转换为已完成。

$.when(
    mercury.Tracking.logUsage("export", GetSelectedExportType(form)).then(null, function() {
        return $.when();//resolved promise
    }),
    mercury.Tracking.logUsage('exportchart', mercury.ChartContainer.currentChartUri(), path).then(null, function() {
        return $.when();//resolved promise
    })
).done(function() {
    form[0].submit(); 
});

然而,返回被拒绝的承诺然后转换为成功似乎是一种不必要的复杂化:

  • 优良作法是以拒绝承诺的形式报告asycnhronous失败,而不是简单地记录错误并返回undefined。
  • window.Tracking.logUsage()可能会在您的代码中的其他位置调用,因此必须将错误视为错误。