【问题标题】:Simple client-side framework/pattern to simplify doing async calls?简单的客户端框架/模式来简化异步调用?
【发布时间】:2012-03-12 02:09:32
【问题描述】:

除了 jQuery(和 jQuery.ui + 验证 + 表单向导插件)之外,我们目前没有使用任何严肃的客户端框架。

在我们的代码中多次出现的问题是:

  1. 我们有一个按钮可以启动对服务器的 Ajax 调用。
  2. 在通话过程中,我们会显示一个带有一些文字的“正在加载”图标
  3. 如果服务器返回结果太快(例如 setTimeout()),to prevent flickering of the waiting icon & text
  4. max(the call returns, a minimal timeout) 之后,我们清除加载图标和文字。
  5. 然后我们要么显示错误文本,如果在 ajax 调用中出现问题(服务器不返回 500,而是一个具有“错误消息”属性的自定义 json。事实上,有时我们有这样一个每个表单字段的响应中的属性...然后我们将错误匹配到表单字段...但我离题了)。
  6. 如果成功,我们会做...一些事情(视情况而定)。

我正在尝试最大程度地减少代码重用,并编写或重用执行此操作的模式/一段代码/框架。虽然我可能不会只为这个用例开始使用全新的重型框架,但我仍然想知道我的选择是什么……也许这样的客户端框架也适用于其他事情。如果有一个轻量级框架不需要我将所有代码颠倒过来,并且我可以只在特定情况下使用,那么我们可能会真正使用它而不是重新发明轮子。

我最近才听说Ember.js - 它适合解决这个问题吗?你会怎么解决呢?

【问题讨论】:

    标签: javascript ajax frameworks ember.js


    【解决方案1】:
    $(function(){
     var buttonSelector = "#button";
     $('body').on({'click': function(evt){
        var $button = $(this);
        $button.toggleClass('loading');
        var time = new Date();
        $.get('some/ajax').then(function(data,text,jqXhr){
       // typical guess at load work
           $button.empty();
           $(data).wrap($button);
        }).fail(function(data,text,jqXhr){
         alert("failed");
        }).done(function(data,text,jqXhr){
           var elapsed = new Date();
          if((elapsed - time) < 200){
            alert("to short, wait");
          }
          $button.toggleClass('loading');
        });
      }},buttonSelector,null);
    });
    

    【讨论】:

    • 谢谢,我正打算这样做。我会接受你的回答,因为它是正确的模式。另外,我在下面提交了我的工作解决方案(不是直接来自您的回答)。
    【解决方案2】:

    工作示例代码(嗯,差不多)

    无论如何,我一直在寻求@DefyGravity 的答案——他的想法很好,但仍然是伪代码/不完全完整。这是我的工作代码(almost working demo,直到 Ajax URL 本身和 UI 调整)

    代码及用法示例:

    jQuery.fn.disable = function() {
        $(this).attr("disabled", "disabled");
        $(this).removeClass("enabled");
    
        // Special handling of jquery-ui buttons: http://stackoverflow.com/questions/3646408/how-can-i-disable-a-button-on-a-jquery-ui-dialog
        $(this).filter("button").button({disabled: true});
    };
    jQuery.fn.enable = function() {
        $(this).removeAttr("disabled");
        $(this).addClass("enabled");
        // Special handling of jquery-ui buttons: http://stackoverflow.com/questions/3646408/how-can-i-disable-a-button-on-a-jquery-ui-dialog
        $(this).filter("button").button({disabled: false});
    };
    
    
    function AjaxCallbackWaiter(ajaxUrl, button, notificationArea, loadingMessage, errorMessage, inSuccessHandler, inFailureHandler) {
        // Every request that takes less than this, will be intentionally delayed to prevent a flickering effect
        // http://ripper234.com/p/sometimes-a-little-sleep-is-ok/
        var minimalRequestTime = 800;
        var loadingIconUrl = 'http://loadinfo.net/images/preview/11_cyrcle_one_24.gif?1200916238';
    
        var loadingImageContent = $("<img class='loading-image small' src='" + loadingIconUrl + "'/><span class='loading-text'>" + loadingMessage + "</span>");
        var errorContentTemplate = $("<span class='error ajax-errors'></span>");
    
        var requestSentTime = null;
    
        button.click(clickHandler);
    
        function displayLoadingMessage() {
            clearNotificationArea();
            notificationArea.html(loadingImageContent);
        }
    
        function clearNotificationArea() {
            notificationArea.html("");
        }
    
        function displayError(message) {
            var errorContent = errorContentTemplate.clone(errorContentTemplate).html(message);
            notificationArea.html(errorContent);
        }
    
        function ajaxHandler(result) {
            var requestReceivedTime = new Date().getTime();
            var timeElapsed = requestReceivedTime - requestSentTime;
            // Reset requestSentTime, preparing it for the next request
            requestSentTime = null;
    
            var sleepTime = Math.max(0, minimalRequestTime - timeElapsed);
    
            function action() {
                clearNotificationArea();
                button.enable();
                if (result) {
                    inSuccessHandler();
                } else {
                    displayError(errorMessage);
                    inFailureHandler();
                }
            }
    
            if (sleepTime <= 0) {
                action();
            } else {
                setTimeout(action, sleepTime);
            }
        }
    
        function failureHandler() {
    
        }
    
        function clickHandler(){
            if (requestSentTime !== null) {
                logError("Bad state, expected null");
            }
            requestSentTime = new Date().getTime();
            displayLoadingMessage();
            button.disable();
            $.get(ajaxUrl, 'json').then(ajaxHandler, failureHandler);
        }
    }
    
    // Usage:
    var ajaxUrl = 'FILL IN YOUR OWN URL HERE';
    var button = $("#clickme");
    var notificationArea = $(".ajax-notification-area");
    
    var waitingMessage = "Doing Stuff";
    var errorMessage = "Not Good<br/> Please try again";
    
    $(document).ready(function(){
      new AjaxCallbackWaiter(
        ajaxUrl,
        button, 
        notificationArea,
        waitingMessage,
        errorMessage,
        function(){
          alert("All is well with the world");
        },
        function(){
          alert("Not good - winter is coming");
        });
    });
    

    【讨论】:

      【解决方案3】:

      只需将 $.ajax 包装在您自己的函数中即可。这样你就可以实现自己的排队等。我建议为此做一个 jquery 组件。它可以变得非常强大,例如您还可以传递 http 标头等。
      关于框架,这取决于您的要求。
      例如,您可能会考虑 Kendo UI,它具有创建数据源的良好框架: http://demos.kendoui.com/web/datasource/index.html.

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-13
        • 1970-01-01
        • 1970-01-01
        • 2017-03-10
        相关资源
        最近更新 更多