简化异步调用的简单客户端框架/模式
Simple client-side framework/pattern to simplify doing async calls?
除了jQuery(以及jQuery.ui+验证+表单向导插件)之外,我们目前没有使用任何严肃的客户端框架。
在我们的代码中出现过几次的问题是:
- 我们有一个按钮,用于启动对服务器的Ajax调用
- 在通话过程中,我们会显示一个带有一些文本的"加载"图标
- 如果服务器返回结果过快(例如<200ms),我们将"睡眠"200毫秒(使用
setTimeout()
),以防止等待图标&文本 - 在
max(the call returns, a minimal timeout)
之后,我们清除加载图标&文本 - 然后,如果ajax调用中出现问题,我们要么显示错误文本(服务器不返回500,而是返回一个具有"错误消息"属性的自定义json。事实上,有时我们在响应每个表单字段中都有这样的属性…然后我们将错误与表单字段匹配…但我跑题了)
- 如果成功,我们会。。。某事(取决于情况)
我正在努力最大限度地减少代码重用,并编写或重用这样做的模式/代码段/框架。虽然我可能不会仅仅为了这个用例而开始使用一个全新的重载框架,但我仍然想知道我的选择是什么。。。也许这样的客户端框架对其他方面也有好处。如果有一个轻量级的框架不需要我把所有的代码都颠倒过来,并且我可以只在特定的情况下使用,那么我们可能会真正使用它,而不是重新发明轮子。
我最近刚听说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");
});
});
相关文章:
- 混合 Web/客户端框架
- 客户端的JavaScript框架
- javascript客户端ORM的框架
- 做全栈JavaScript框架在客户端或服务器上创建HTML
- 是否有一种搜索引擎友好的方法可以将服务器端呈现的 HTML 与客户端 MVVM/MVC 框架相结合
- 客户端验证 在具有实体框架的 MVC 中
- Javascript 客户端框架与 Rails JSON API - 如何进行集成测试
- Ajax 客户端框架运行 HTML 代码时出错
- 为什么现在对客户端框架有如此大的推动力
- 在html/css/js之上是否有任何富Web客户端框架
- 当应用程序使用客户端和服务器端 MVC 框架时,如何处理路由
- 我需要客户端框架吗?(网络应用程序)
- 对于非SPA,我应该使用Ember或React这样的客户端框架吗
- JS框架,用于客户端与rest api通信
- 简化异步调用的简单客户端框架/模式
- 是否存在客户端+服务器端MVC JS框架
- 在哪里托管Wakanda[客户端/服务器端纯JS'框架']
- 使用JS框架开发数据库客户端应用程序
- 我应该为客户端和服务器代码使用不同的单元测试框架吗
- 使用客户端框架的优点和缺点