Javascript - 异步函数导致错误的顺序

时间:2016-08-25 17:25:33

标签: javascript asynchronous

我正在Javascript中构建照片上传器并阅读已上传的照片我已经使用此代码:

    // Populate with existing photos
    var index;
    for (index = 0; index < params.photosToPopulate.length; ++index) {

        // Get the data of the image
        getDataUri(params.photosToPopulate[index], params, function(dataURI){
            // Get the Blob
            dataURItoBlob(dataURI, function(dataurl){

                var blob = URL.createObjectURL(dataurl);

                // fileItem
                var fileItem = document.createElement("div");
                fileItem.setAttribute('angle', 0);
                fileItem.setAttribute('blob', blob);
                fileItem.className = 'imageloaderplusFile';
                filesdiv.appendChild(fileItem);

                // fileImg
                var fileImg = document.createElement("div");
                fileImg.className = 'imageloaderplusImage';
                fileImg.style.backgroundImage = 'url(' + dataURI + ')';
                fileItem.appendChild(fileImg);

                // fileRotate
                var fileRotate = document.createElement("div");
                fileRotate.className = 'imageloaderRotate';
                fileRotate.setAttribute('title', 'Rotate');
                fileItem.appendChild(fileRotate);
                fileRotate.onclick = function(){

                    var angle;

                    switch(parseInt(this.parentNode.getAttribute('angle'))){
                        case 0:
                            angle = 90;
                            break;  
                        case 90:
                            angle = 180;
                            break;
                        case 180:
                            angle = 270;
                            break;
                        case 270:
                            angle = 0;
                            break;
                    }

                    this.parentNode.setAttribute('angle', angle);

                    // css
                    var image = this.parentNode.firstChild;
                    image.style.webkitTransform = 'rotate(' + angle + 'deg)'; 
                    image.style.mozTransform = 'rotate(' + angle + 'deg)'; 
                    image.style.msTransform = 'rotate(' + angle + 'deg)';
                    image.style.oTransform = 'rotate(' + angle + 'deg)';
                    image.style.transform = 'rotate(' + angle + 'deg)';

                    // draw
                    ImageLoaderPlus.draw(this.parentNode, params);
                }

                // fileRemove
                var fileRemove = document.createElement("div");
                fileRemove.className = 'imageloaderRemove';
                fileRemove.setAttribute('title', 'Remove');
                fileItem.appendChild(fileRemove);
                fileRemove.onclick = function(){
                    this.parentNode.parentNode.removeChild(this.parentNode);
                }

                // draw
                ImageLoaderPlus.draw(fileItem, params); 

            });
        });

    } // End For Loop

在For循环中我已经订购了照片,但有时由于异步函数getDataUri()和dataURItoBlob(),For循环中项目的顺序不会转换为de UI / DOM中的顺序照片显示的顺序不正确。我怎样才能防止这种情况发生?

异步函数是这样的:

    function getDataUri(url, params, callback) {

        var image = new Image();
        var canvas = document.createElement("canvas");
        var ctx = canvas.getContext("2d");
        //image.crossOrigin = "anonymous";  // This enables CORS

        // get scale
        var scale = (params.resize && (image.width > params.maxWidth || image.height > params.maxHeight)) ? Math.min(params.maxWidth / image.width, params.maxHeight / image.height) : 1;

        image.onload = function (event) {
            try {
                canvas.width = Math.round(image.width * scale);
                canvas.height = Math.round(image.height * scale);
                ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
                //console.log( ctx.canvas.toDataURL('image/jpeg', params.jpegQuality) );
                result = ctx.canvas.toDataURL('image/jpeg', params.jpegQuality)
                callback(result);
            } catch (e) {
                alert(e);
            }

        };
        image.src = url;
    }       

    // To convert URL to Blob
    function dataURItoBlob(dataURI, callback) {
            // convert base64 to raw binary data held in a string
            // doesn't handle URLEncoded DataURIs

            var byteString;
            if (dataURI.split(',')[0].indexOf('base64') >= 0) {
                byteString = atob(dataURI.split(',')[1]);
            } else {
                byteString = unescape(dataURI.split(',')[1]);
            }

            // separate out the mime component
            var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];

            // write the bytes of the string to an ArrayBuffer
            var ab = new ArrayBuffer(byteString.length);
            var ia = new Uint8Array(ab);
            for (var i = 0; i < byteString.length; i++) {
                ia[i] = byteString.charCodeAt(i);
            }


            try {
                result = new Blob([ab], {type: mimeString});
                //return new Blob([ab], {type: mimeString});
            } catch (e) {
                // The BlobBuilder API has been deprecated in favour of Blob, but older
                // browsers don't know about the Blob constructor
                // IE10 also supports BlobBuilder, but since the `Blob` constructor
                //  also works, there's no need to add `MSBlobBuilder`.
                var BlobBuilder = window.WebKitBlobBuilder || window.MozBlobBuilder;
                var bb = new BlobBuilder();
                bb.append(ab);
                result = bb.getBlob(mimeString);
                //return bb.getBlob(mimeString);
            }

            callback(result);       
    }

有关如何避免此问题的任何线索?

最诚挚的问候,

1 个答案:

答案 0 :(得分:1)

您可以通过在接收数据时将dataurl值存储在数组中来解决此问题,但是在该数组中的正确索引处。然后当你计算出你收到了所有dataurl个值时,就会对该数组执行循环并像现在一样执行元素创建代码。

// Intermediate array to store the dataURI and dataurl values in order
var urls = [];
var URIs = [];
// Keep count of how many dataurl values we received
var leftOver = params.photosToPopulate.length;
// Iterate in a way that you create a new closure on every iteration, 
// each iteration has its proper index variable
params.photosToPopulate.forEach(function (photo, index) {
    // Get the data of the image
    getDataUri(photo, params, function(dataURI){
        // Store at the right place in our array
        URIs[index] = dataURI;
        // Get the Blob
        dataURItoBlob(dataURI, function(dataurl){
            // Only store the url at the right place in our array
            urls[index] = dataurl;
            // ... and update the count
            leftOver--;
            // All done? Then iterate over the dataurl values in the correct order
            if (!leftOver) urls.forEach(function(dataurl, index) {
                var dataURI = URIs[index]; // get correct dataURI
                var blob = URL.createObjectURL(dataurl);
                // fileItem
                var fileItem = document.createElement("div");
                // ...etc, all your element creation code comes here, unchanged. 
                // ...

                // draw
                ImageLoaderPlus.draw(fileItem, params); 
            });
        });
    });
});