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

标签 javascript asynchronous

我正在用 Javascript 构建一个照片 uploader 并读取已上传的照片,我有以下代码:

    // 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 循环中的项目顺序不会转换为 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);       
    }

有什么线索可以避免这个问题吗?

最诚挚的问候,

最佳答案

您可以通过在收到 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); 
            });
        });
    });
});

关于Javascript - 异步函数导致顺序错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39151310/

相关文章:

javascript - 如何在 REST API 中对特定模型的所有字段使用一个更新函数?

javascript - 链接元素上的 click() 返回 TypeError ... 为什么?

javascript - SASS 编译可以,但 Gulp 不行

javascript - 如果两个 promise 同时解决,这是否可能是竞争条件?

c# - 异步调用 WriteAsync,我怎么知道它何时完成?

javascript - 尽管 JSON 有效并且返回代码为 201,jQuery Ajax 返回 "parsererror"

javascript - 进行两个系列的异步调用,中间有延迟

Javascript (ES6) 异步回调执行

asp.net - 在asp.net中实时显示命令行程序的输出

javascript - Handlebars.js 条件语句 {{#if expression}} ... {{else}} ... {{/iif}} 错误