如何在javascript中同步异步方法?

时间:2015-01-27 18:26:07

标签: javascript

我有一个图像处理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仅为300KB。因此,首先完成图像3的转换,并且阵列中图像的最终顺序为3,1,2(或3,2,1)。

如何同步processImage的执行,以便仅在前一个图像的转换完成后处理下一个图像?

3 个答案:

答案 0 :(得分:2)

我认为你应该看看javascript中的锁:

https://github.com/Wizcorp/locks

答案 1 :(得分:1)

Locks are great,@ Esse回答。我还建议您查看Fibers(这是我通常使用的)和Promises.js

This is a great article关于Meteor框架中的Async。它很好地概述了光纤的工作原理。

答案 2 :(得分:1)

我会使用Promises来解决这样的问题。我喜欢实现Q标准的Promises/A+库。

More on Promises on HTML5 Rocks

使用QQimage库制作了一个小图片加载脚本,在与问题类似的情况下显示了Promise的原则:

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);
});