我有一个图像处理javascript。通过ID为"image_input"的文件输入,用户可以选择上传无限数量的图像。当用户上传图像时,下面的jQuery代码会捕获它们并为每个图像调用我的图像处理代码。
$('#image_input').change(function() {
var input = $(this);
image_count = input[0].files.length;
for (var i = 0; i < image_count; i++) {
Uploader.processImage(input[0].files[i]);
}
});
流程图像函数创建一个新的 HTML img 元素,并将用户上传的图像加载到其中。脚本会等到加载图像,然后将其转换为合适的格式和大小。最后,图像被保存到一个数组中:Uploader.images。
Uploader.processImage = function(image) {
var image_element = document.createElement('img');
var image_url = window.URL.createObjectURL(image);
image_element.onload = function() {
image_data = convert(this);
Uploader.images.push(dataUriToBlob(image_data));
}
image_element.src = image_url;
}
我希望图像按照上传的顺序存储在数组中。问题是 onload 函数是异步的,这意味着我无法控制图像的保存顺序。例如,我选择上传 3 张图片。映像 1 和映像 2 的大小均为 10MB,但映像 3 的大小仅为 300 KB。因此,首先完成图像 3 的转换,数组中图像的最终顺序为 3, 1, 2(或 3, 2, 1)。
如何同步 processImage 的执行,以便仅在前一个图像的转换完成后处理下一个图像?
你应该看看javascript中的锁:
https://github.com/Wizcorp/locks
正如@Esse回答的那样,锁很棒。 我还建议查看Fibers(这是我通常使用的)和Promises.js。
这是一篇关于 Meteor 框架中异步的好文章。 不过,它很好地概述了纤维的工作原理。
我会使用承诺来解决这样的问题。我喜欢实现 Promises/A+ 标准的 Q 库。
更多关于 HTML5 摇滚的承诺
使用 Q 和 Qimage 库制作了一个小的图像加载脚本,在类似于问题中的情况中显示了承诺的原则:
var arrOfImgUrls = [url1, url2, url3];
//Loads images from an array of URLs
function loadImages(urls) {
var promises = [];
for (var i = 0; i < urls.length; i++) {
//Qimage loads and image from an URL and returns a Promise.
//If the Promise is fullfilled we get an <img> node
//as the resolve value.
//
//We push the Promises on to an array
promises.push(Qimage(urls[i]))
}
//Return the array of Promises
return promises;
}
//Q.all() returns a promise that is fulfilled with an array
//containing the fulfillment value of each promise, or is rejected
//with the same rejection reason as the first promise to be rejected.
Q.all(loadImages(arrOfImgUrls))
//If all Promises are fullfilled the the resolve callback is called
.then(function (imgs) {
//We get an array of <img> nodes in the same order as the
//'arrOfImgUrls'-array
console.log(imgs);
},
//Else the reject callback is called with the same rejection
//reason as the first promise to be rejected.
function (error) {
console.log(error);
});