我正在研究一种方法,我可以将php程序的多个实例更新到同一版本而不需要太多努力。
我的软件会检查RSS源,其中包含有关最新版本的信息。如果它看到有可用的更新,则会显示指向“更新”页面的链接。当用户点击Update链接时,我有一个jquery函数,用于更新每个需要一次更新的文件:
$.getJSON('http://softwareserver.com/updateFileList.php?fromver=1.0', function(data) {
var filesToDo = data.length;
$.each(data, function(num, file) {
num = num + 1;
action = file.charAt(0);
name = file.substring(1);
if ( action == "+" )
{
$('#upsole').append("<p><strong>Adding</strong> " + name + ". . .</p>");
$.get("{$var['sbpurl']}/updateAction.php", { action: "add", file: name, revision: "{$TMP['rev']}" } );
}
else if ( action == "-" )
{
$('#upsole').append("<p><strong>Removing</strong> " + name + ". . .</p>");
$.get("{$var['sbpurl']}/updateAction.php", { action: "remove", file: name, revision: "{$TMP['rev']}" } );
}
else if ( action == "~" )
{
$('#upsole').append("<p><strong>Updating</strong> " + name + ". . .</p>");
$.get("{$var['sbpurl']}/updateAction.php", { action: "update", file: name, revision: "{$TMP['rev']}", version: "{$TMP['ver']}" } );
}
var completed = num / filesToDo * 100;
$('#barcolor').css('width', completed + '%');
$('#numProgress').html(completed.toFixed(0));
if ( completed == 100 )
{
$('#conutt').html('<a href="index.php" class="button"> Continue > </a>');
$('#upsole').append("<p><strong>Update Complete</strong></p>");
}
});
});
我在div容器中显示每个文件名,因为它正在更新;我还有一个进度条,从0-100%开始,每个文件都被更新,直到所有文件都被更新..但是当它全部完成时它只是从0到100。它实际上并没有显示进度,因为每个文件之间的更新都像我想要的那样。
我希望我的进度条从0%变为7%,15%等,直到达到100%但是没有任何事情发生,直到它全部完成..所以我说,它只是从0%到100%。
$ .each不是最佳解决方案吗?
答案 0 :(得分:1)
不,$.each
不是这项工作的正确工具。您的主要问题是浏览器中的JavaScript是单线程的,所以您的所有DOM更新:
$('#upsole').append(...)
$('#barcolor').css(...)
$('#numProgress').html(...)
将排队等待处理。那么浏览器什么时候重新获得控制权?当$.each
完成后。您会看到结果:用户看到事情从一无一到一步完成。您还需要考虑$.get
的异步性质。
每次更新DOM后,您需要将控制权交还给浏览器。您有一堆$.get
调用,因此您可以使用他们的成功回调来交换您的DOM更改与浏览器对这些更改的响应。像这样:
$.getJSON('http://softwareserver.com/updateFileList.php?fromver=1.0', function(data) {
var filesToDo = data.length;
var next_one = function() {
var file = data.shift();
if(!file) {
// If `data` is empty then we're all done so we can put the UI into
// the "update complete" state and end the process by not calling
// next_one() again.
$('#conutt').html('<a href="index.php" class="button"> Continue > </a>');
$('#upsole').append("<p><strong>Update Complete</strong></p>");
return;
}
// Set up the next iteration by parsing `file`. We put the `$.get` stuff
// into an object so that we only have one `$.get` call; the reason for
// this will be clear shortly.
var action = file.charAt(0);
var name = file.substring(1);
var get = { };
if(action == '+') {
get = {
msg: '<p><strong>Adding</strong> ' + name + '...</p>',
url: "{$var['sbpurl']}/updateAction.php",
params: { action: "add", file: name, revision: "{$TMP['rev']}" }
};
}
else if(action == '-') {
//...
}
else if(action == '~') {
//...
}
// Tell them what we're about to do...
$('#upsole').append(get.msg);
// This `$.get` call is asynchronous so the browser will get control here
// and any pending DOM updates will be applied.
$.get(get.url, get.params, function() {
// Update the DOM with the latest status.
var completed = (filesToDo - data.length) / filesToDo * 100;
$('#barcolor').css('width', completed + '%');
$('#numProgress').html(completed.toFixed(0));
// And trigger the next iteration.
next_one();
});
};
// Crank it up.
next_one();
});
基本思想是迭代data
直到它为空,每次迭代都会移除data
的第一个元素,这样我们就可以检测到data
的结束(以及我们的结束)通过查看它何时返回undefined
(这是假的)来迭代)。每次迭代都会触发$.get
,它会将控制权返回给浏览器以允许更新DOM。然后$.get
回调将触发下一次迭代。
错误处理等问题留给读者练习。
答案 1 :(得分:1)
c0nfus3d1,我看到你有@mu的答案,但也许你想看到我在重大中断之前开始准备的解决方案。
据我所知,.each()
对于工作很有用,而且您的代码只需要进行非常轻微的修改即可使其正常工作。
但是,它还可以从进一步的mod中受益,以提供更整洁,更易读的版本:
$.getJSON('http://softwareserver.com/updateFileList.php?fromver=1.0', function(data) {
var filesToDo = data.length;
var filesDone = 0;
var activityStr = "<p><strong>%s1</strong>%s2</p>";//activity message template
function showProgress() {
filesDone++;
var completed = 100 * filesDone / filesToDo;
$('#barcolor').css('width', completed + '%');
$('#numProgress').html(completed.toFixed(0));
if ( filesDone == filesToDo ) {
$('#conutt').html('<a href="index.php" class="button"> Continue > </a>');
$('#upsole').append(activityStr.replace('%s1', 'Update Complete').replace('%s2', ''));
}
}
$.each(data, function(num, file) {
var dataObj = {//data common to all cases below.
file: file.substring(1),
revision: "{$TMP['rev']}"
},
a, d;
switch (file.charAt(0)) {
case "+":
a = 'Adding';
d = $.extend({action:"add"}, dataObj);
break;
case "-":
a = "Removing";
d = $.extend({action:"remove"}, dataObj);
break;
case "~":
a = "Updating";
d = $.extend({action:"update", version:"{$TMP['ver']}"}, dataObj);
}
$('#upsole').append(activityStr.replace('%s1', a).replace('%s2', ' ' + d.file + '. . .'));
$.get("{$var['sbpurl']}/updateAction.php", d).done(showProgress);
});
});
未测试
注意:
$.extend()
用于合并常规和特定于案例的对象,以构建内部$.get
数据。.replace()
应用于字符串模板来生成进度消息。showProgress()
以响应每个内部.get()
调用的完成。.get()
请求是以非常快的速度连续发出的,但响应将按照以及何时 - 以任何顺序 - 处理,从服务器返回。也许这包括一些你可以使用的想法。