仅在 javascript 循环完成后执行 ajax 调用
Posted
技术标签:
【中文标题】仅在 javascript 循环完成后执行 ajax 调用【英文标题】:Execute ajax call only after javascript loop has finished 【发布时间】:2015-06-26 22:15:57 【问题描述】:下面是我使用的代码,它基本上传递了多个要上传的文件。在循环中,每个文件都在客户端调整大小,然后上传。
我想在循环完成上传照片后执行 ajax 调用。 ajax 调用基本上是重新加载特定的 div 并刷新照片。
如何防止 ajax 调用在循环完成之前执行。
if (window.File && window.FileReader && window.FileList && window.Blob)
var files = document.getElementById('filesToUpload').files;
for(var i = 0; i < files.length; i++)
resizeAndUpload(files[i]);
// when loop finished, execute ajax call
$.ajax
(
type: "POST",
url: "photos.php",
data: dataString,
success: function(html)
$("#photo-body").html(html);
);
function resizeAndUpload(file)
var reader = new FileReader();
reader.onloadend = function()
var tempImg = new Image();
tempImg.src = reader.result;
tempImg.onload = function()
var MAX_WIDTH = 382.25;
var MAX_HEIGHT = 258.5;
var tempW = tempImg.width;
var tempH = tempImg.height;
if (tempW > tempH)
if (tempW > MAX_WIDTH)
tempH *= MAX_WIDTH / tempW;
tempW = MAX_WIDTH;
else
if (tempH > MAX_HEIGHT)
tempW *= MAX_HEIGHT / tempH;
tempH = MAX_HEIGHT;
var canvas = document.createElement('canvas');
canvas.width = tempW;
canvas.height = tempH;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0, tempW, tempH);
var dataURL = canvas.toDataURL("image/jpeg");
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(ev)
document.getElementById('filesInfo').innerHTML = 'Upload Complete';
;
xhr.open('POST', 'upload-resized-photos.php', true);
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
var data = 'image=' + dataURL;
xhr.send(data);
reader.readAsDataURL(file);
var _validFileExtensions = [".jpg", ".jpeg", ".bmp", ".gif", ".png"];
function Validate(oForm)
var arrInputs = oForm.getElementsByTagName("input");
for (var i = 0; i < arrInputs.length; i++)
var oInput = arrInputs[i];
if (oInput.type == "file")
var sFileName = oInput.value;
if (sFileName.length > 0)
var blnValid = false;
for (var j = 0; j < _validFileExtensions.length; j++)
var sCurExtension = _validFileExtensions[j];
if (sFileName.substr(sFileName.length - sCurExtension.length, sCurExtension.length).toLowerCase() == sCurExtension.toLowerCase())
blnValid = true;
break;
if (!blnValid)
alert("Sorry, " + sFileName + " is invalid, allowed extensions are: " + _validFileExtensions.join(", "));
return false;
return true;
【问题讨论】:
你需要从resizeAndUpload
返回promise。然后使用$.when()
等待所有的promise 完成。
你能告诉我如何在上面的代码中做到这一点。非常感谢
可以添加resizeAndUpload
的代码吗?
修改了上面的帖子以包含功能
【参考方案1】:
您可以将 $ajax 调用包装在一个函数中,并在最终循环结束时调用该函数。
(只是脚本的顶部)
if (window.File && window.FileReader && window.FileList && window.Blob)
function loopFinished()
$.ajax
(
type: "POST",
url: "photos.php",
data: dataString,
success: function(html)
$("#photo-body").html(html);
);
var files = document.getElementById('filesToUpload').files;
for(var i = 0; i < files.length; i++)
resizeAndUpload(files[i]);
if (files.length+1 == [i])
loopFinished();
【讨论】:
【参考方案2】:您可以使用任何 Promise 库来执行此操作。这是使用 jQuery Promise 的示例
(function ($)
var files = [1, 2, 3, 4],
allPromises = [];
for (var i = 0; i < files.length; i++)
var promise = resizeAndUpload(files[i]);
allPromises.push(promise);
$.when.apply($, allPromises).done(function ()
makeAjaxCall();
);
function makeAjaxCall()
console.log('Put Ajax call here');
function resizeAndUpload(file)
var defer = $.Deferred();
//Set timeout simulates your long running process of processing file
setTimeout(function ()
console.log('processing file ' + file);
defer.resolve();
, 2000);
return defer.promise();
)(jQuery);
这是一个 jSFiddle http://jsfiddle.net/x6oh471f/2/
【讨论】:
【参考方案3】:resizeAndUpload()
函数中的一个或多个方法必须异步发生。这意味着他们将在您的其余 javascript 运行时在后台做他们的事情,并且他们应该在完成时触发一个事件。一旦这些方法中的最后一个完成并触发了事件,您将需要调用 ajax 方法。例如,fileReader 方法是异步的。这意味着您可能需要执行以下操作:
FileReader.onloadend = function()
totalFilesLoaded = totalFilesLoaded + 1;
if (totalFilesLoaded == files.length)
//all files have been uploaded, run $ajax
编辑:现在您已经上传了其余代码,请尝试以下操作:
window.totalFilesLoaded = 0;
var files = document.getElementById('filesToUpload').files;
window.totalFilesToLoad = files;
if (window.File && window.FileReader && window.FileList && window.Blob)
for(var i = 0; i < files.length; i++)
resizeAndUpload(files[i]);
单独的ajax函数:
window.runAjax = function()
$.ajax
(
type: "POST",
url: "photos.php",
data: dataString,
success: function(html)
$("#photo-body").html(html);
);
function resizeAndUpload(file)
var reader = new FileReader();
reader.onloadend = function()
...
xhr.onreadystatechange = function(ev)
document.getElementById('filesInfo').innerHTML = 'Upload Complete';
window.totalFilesLoaded++;
if (window.totalFilesLoaded == window.totalFilesToLoad.length)
window.runAjax()
;
...
reader.readAsDataURL(file);
【讨论】:
我会在哪里添加该代码。我尝试在 for 循环之后添加它。文件上传,但 ajax 确实被调用。我也在进入循环之前设置了 totalFilesLoaded = 0。 runAjax 永远不会被执行。如果我添加一个警报(files.length),我会得到未定义的。 抱歉,文件也需要是全局的,将var files = document.getElementById('filesToUpload').files;
声明放在顶部,在带有 totalFilesLoaded 的 if 语句之外 - 我再次编辑了我的回复 - 抱歉,我没有时间测试我自己
发生了一些奇怪的事情。我有上面的一切。如果我在 totalFilesLoaded 下放置一个警报(totalFilesLoaded),则不会发出任何警报。同样由于某种原因, runAjax 从未被调用。我迷路了。
这很奇怪,你的意思是你直接在下面提醒它var totalFilesLoaded = 0;
?并且根本没有出现警报框?你可能想把它放在jsfiddle 或类似的地方。以上是关于仅在 javascript 循环完成后执行 ajax 调用的主要内容,如果未能解决你的问题,请参考以下文章