简单的客户端框架/模式,以简化异步调用?

时间:2012-02-21 18:31:25

标签: javascript ajax frameworks ember.js

除了jQuery(以及jQuery.ui + validation + form wizard插件)之外,我们目前还没有使用任何严肃的客户端框架。

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

  1. 我们有一个按钮,用于启动对服务器的Ajax调用。
  2. 在通话过程中,我们会显示带有文字的“加载”图标
  3. 如果服务器返回的结果太快(例如<200毫秒),我们会“睡眠”200毫秒(使用setTimeout()),to prevent flickering of the waiting icon & text
  4. max(the call returns, a minimal timeout)之后,我们会清除加载图标&amp;文本。
  5. 然后我们要么显示错误文本,如果ajax调用中有问题(服务器不返回500,而是自定义json有“错误消息”属性。事实上,有时我们有这样的每个表单字段的响应中的属性...然后我们将错误匹配到表单字段...但我离题了。
  6. 如果成功,我们会做某事(取决于具体情况)。
  7. 我正在尝试最小化代码重用,并编写或重用执行此操作的模式/代码/框架。虽然我可能不会仅仅为这个用例开始使用一个全新的重型框架,但我仍然想知道我的选择是什么......也许这样的客户端框架对其他事情也有好处。如果有一个轻量级框架不需要我将我的所有代码颠倒过来,并且我可以只使用特定情况,那么我们实际上可能会使用它而不是重新发明轮子。

    我刚刚听说Ember.js - 它是否适合解决这个问题?你会如何解决它?

3 个答案:

答案 0 :(得分:4)

$(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);
});

答案 1 :(得分:0)

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

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

代码&amp;用法示例:

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");
    });
});

答案 2 :(得分:0)

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