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

Simple client-side framework/pattern to simplify doing async calls?

本文关键字:客户端 框架 模式 简单 异步 调用      更新时间:2023-09-26

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

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

  1. 我们有一个按钮,用于启动对服务器的Ajax调用
  2. 在通话过程中,我们会显示一个带有一些文本的"加载"图标
  3. 如果服务器返回结果过快(例如<200ms),我们将"睡眠"200毫秒(使用setTimeout()),以防止等待图标&文本
  4. max(the call returns, a minimal timeout)之后,我们清除加载图标&文本
  5. 然后,如果ajax调用中出现问题,我们要么显示错误文本(服务器不返回500,而是返回一个具有"错误消息"属性的自定义json。事实上,有时我们在响应每个表单字段中都有这样的属性…然后我们将错误与表单字段匹配…但我跑题了)
  6. 如果成功,我们会。。。某事(取决于情况)

我正在努力最大限度地减少代码重用,并编写或重用这样做的模式/代码段/框架。虽然我可能不会仅仅为了这个用例而开始使用一个全新的重载框架,但我仍然想知道我的选择是什么。。。也许这样的客户端框架对其他方面也有好处。如果有一个轻量级的框架不需要我把所有的代码都颠倒过来,并且我可以只在特定的情况下使用,那么我们可能会真正使用它,而不是重新发明轮子。

我最近刚听说Ember.js,它适合解决这个问题吗?你将如何解决它?

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

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

工作样本代码(好吧,差不多)

无论如何,我想要的是@DefyGravity的答案——他的想法很好,但仍然是伪代码/不完全完整。这是我的工作代码(几乎是工作演示,直到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");
    });
});