每次mocode()
触发时,您似乎都会创建一个新的<img />
并替换以前的。通过重复使用相同的内容,您将获得更平滑的效果<img>
- 只需更改其 src。
我不确定你的代码是如何工作的,所以很难确定,但我认为你需要这样的东西:
function graphError() {
alert('Graph: reload failed');
}
var $graphImg = $("#GraphImage").on('error', graphError);
var tid = setInterval(mycode, 20000);
function mycode() {
var theDate = new Date();
var mili = theDate.getUTCDate() + theDate.toLocaleTimeString() + theDate.getMilliseconds();
$.ajax({
url: '@Url.Action("Chart", "Home", new {ForceNoCache = "theDate"})',
}).done(function(srcURL) {
$graphImg.attr('src', srcURL.replace("theDate", mili));
}).error(graphError);
}
您可能需要以不同的方式构建 url,并且稍微考虑一下可以使错误消息更具体。
编辑
Tyco,您的解决方案看起来不错,如果可行,您可能会想坚持下去。同时,我一直在使用类似的想法,但以 jQuery 的 Deferreds 为中心的代码却截然不同。如果您没有使用它们,它们会有点令人兴奋,但是当您有异步任务时它们非常有用。
在您的情况下,您有三个连续的异步任务,获取图形 URL,加载图形图像,并淡出以前的图形以显示新版本。
对此进行编码相当简单,但代码需要具有容错性——特别是它需要满足服务器响应(URL 和图像本身)以错误的顺序返回或在下一次触发setInterval
. 通过提供取消在前一次迭代中建立的功能链的方法,延迟提供了极大的帮助。
间隔 20 秒应该没有问题,但有一天互联网/服务器可能运行异常缓慢,或者您可能决定减少间隔。
除非你以前使用过 Deferreds,否则下面的代码看起来很陌生,但除非我出错,否则它应该可以完成工作。
Javascript:
$(function() {
var $graphImg1 = $("#GraphImage1");
var $graphImg2 = $("#GraphImage2");
var promises = {
fetchGraphUrl: null,
loadImg: null,
fadeOut: null
};
var graph_errors = {
threshold: 5,//set low for testing, higher in production environment.
count: 0
};
var interval = 5;//seconds
$graphImg2.on('error', function() {
if(promises.loadImg) {
promises.loadImg.reject();
}
}).on('load', function() {
if(promises.loadImg) {
promises.loadImg.resolve();
}
});
function graph_fetchURL(milli) {
if(promises.fetchGraph) {
promises.fetchGraph.reject(milli, 'fetchURL', 'timeout');
}
var dfrd = promises.fetchGraph = $.Deferred().fail(function() {
jqXHR.abort();
});
var jqXHR = $.ajax({
url: '@Url.Action("Chart", "Home", new {ForceNoCache = "theDate"})'
}).done(function(srcURL) {
dfrd.resolve(milli, srcURL);
}).fail(function(jqXHR, textStatus, errorThrown) {
dfrd.reject(milli, 'ajax', textStatus);
});
return dfrd.promise();
}
function graph_loadImg(milli, srcURL) {
if(promises.loadImg) {
promises.loadImg.reject(milli, 'loadImg', 'timeout');
}
//An extra deferred is needed here because $graphImg2's handlers don't know about milli.
var dfrd = $.Deferred();
promises.loadImg = $.Deferred().done(function() {
dfrd.resolve(milli);
}).fail(function() {
dfrd.reject(milli, 'loadGraph', 'load error');
});
$graphImg2.attr('src', srcURL.replace("theDate", milli));
return dfrd.promise();
}
function graph_fade(milli) {
if(promises.fadeOut) {
promises.fadeOut.reject(milli, 'fade', 'timeout');
}
promises.fadeOut = $.Deferred();
$graphImg2.show();
$graphImg1.fadeOut('fast', function() {
promises.fadeOut.resolve(milli);
});
return promises.fadeOut.promise();
}
function graph_swap() {
$graphImg1.attr('src', $graphImg2.attr('src')).show();
$graphImg2.hide();
}
function graph_error(timestamp, phase, txt) {
var txt = txt ? (' (' + txt + ')') : '';
console.log(timestamp + ': fetchGraph failed in the ' + phase + ' phase' + txt);
if(++graph_errors.count >= graph_errors.threshold) {
clearInterval(tid);
console.log('fetchGraph errors exceeded threshold (' + graph_errors.threshold + ')');
}
return $.Deferred().promise();//an unresolved, unrejected promise prevents the original promise propagating down the pipe.
}
function fetchGraph() {
var now = new Date();
var milli = now.getUTCDate() + now.toLocaleTimeString() + now.getMilliseconds();
graph_fetchURL(milli)
.pipe(graph_loadImg, graph_error)
.pipe(graph_fade, graph_error)
.pipe(graph_swap, graph_error);//this .pipe() chain is the glue that puts everything together.
}
fetchGraph();
var tid = setInterval(fetchGraph, interval * 1000);
});
CSS:
#graphWrapper {
position: relative;
float: left;
margin-right: 20px;
}
#GraphImage, #GraphImage2 {
position: absolute;
left: 0;
top: 0;
width: XXpx;
height: YYpx;
}
#GraphImage2 {
display: none;
}
HTML:
<div id="graphWrapper">
<img id="GraphImage1" alt="Graph of Results" src="" />
<img id="GraphImage2" alt="" src="" />
</div>
正如您将看到的,所有内容都组织成一堆相当简洁的函数,每个函数都是一个共同主题的变体,即:-
- 拒绝上一次迭代中任何未完成的同类任务
- 创建一个可以在下一次迭代中被拒绝的 deferred
- 执行任务本身
- 返回从 Deferred 派生的承诺
最后一个任务,graph_swap()
,很简单,错误处理程序graph_error()
略有不同。
有关详细信息,请参阅代码中的注释。
除了处理错误和延迟的服务器响应之外,这种方法的一个主要优点是主迭代器函数fetchGraph()
变得非常简单。真正聪明的一行是一组链式pipe()
命令,它们对任务进行排序并将任何错误路由到错误处理程序。
我已经尽可能多地对此进行了测试,并认为就像您自己的解决方案一样,它将提供平稳的过渡。