【前端】关于在for循环里面执行异步脚本导致变量都采用最后的一个变量问题

问题描述:

最近在修正完成一个html5多图片批量上传功能时候,需要先读取本地的图片然后预览,用到了FileReader的onload方法来读取base64字符串。

问题在于,假如一次性读取多个图片选择多个图片的时候,该方法可以正确执行图片的个数,但是最后读取到的file信息永远是文件列表中最后一个。

问题代码如下:

                var _vars={};
                for(var i=0;i< oFiles.length;i++){
                    var oFile=oFiles[i];
                    _vars["oFile"+i]=oFile;
                    console.log("外层loop的index:");
                    console.log(i);
                    if(!new RegExp("(jpg|jpeg|gif|png)+","gi").test(oFile.type)){
                        ///alert("照片上传:文件类型必须是JPG、JPEG、PNG或GIF!");
                        continue;
                    }

                    var _listitemElement=$(tpl_list_item.render({}));
                    _vars["element"+i]=_listitemElement;

                    var _img_preview=_listitemElement.find('[ui="preview"]');
                    _vars["preview"]=_img_preview;
                    var _btn_delete=_listitemElement.find('[ui="btn-delete"]');
                    _vars["btn_delete"]=_btn_delete;

                    innerTools.getBase4FromImgFile(oFile,function(base64imgData){
                        console.log("当前的i:");
                        console.log(i);
                        console.log(oFile);
                        _img_preview.attr("src",base64imgData);
                        _listitemElement.hide();
                        rootEL.append(_listitemElement);
                        var _show_del=settings.showDeleteButton(rootEL,_listitemElement,oFile,base64imgData);
                        if(_show_del==true){
                            _btn_delete.show();
                        }
                        else if(_show_del==false){
                            _btn_delete.hide();
                        }
                        var _res=settings.onFileHanding(rootEL,_listitemElement,oFile,base64imgData);

                        if(_res==true){
                            _listitemElement.show();
                        }
                        else{
                            _listitemElement.hide();
                        }
                        me.initListElementEvents(_btn_delete,rootEL,_listitemElement,oFile,base64imgData);

                    });
                }



完整代码如下【请注意对比,为什么用interval定时检测执行】:



/**
 * 这是html5的图片批量上传组件。
 */
define("ui.img-muti-uploader",function(require,exports,module){


    var tpls=require("tpl.common-ui");
    var tpl_add_button=laytpl(tpls["img-muti-uploader-add-button"]);
    var tpl_list_item=laytpl(tpls["img-muti-uploader-listitem"]);
    var appData={};
    var rootEL="";
    var _file_add="";
    var settings={
        wrapper:""
        ,showDeleteButton:function(ListContainer,itemElement,file,srcBase64){
            return true;
        }//是否显示删除按钮,假如返回的是true,那么显示,否则不显示。
        ,onFileSelected:function(files){

        }//--当选择一个或多个时候触发该方法。
        ,onFileHanding:function(ListContainer,itemElement,file,srcBase64){

            return true;
        }//在渲染上传文件单元时候触发该方法,返回true时候就显示,否则不显示。应用场景举例:当选择合适的图片时候,组件就会渲染file item模板,然后将有效图片的base64带前缀赋予图片,当然,最后还会加入到图片列表容器显示出来,
        //假如你要做每张图片都上传到服务器然后按照返回的url地址显示的话,没有上传成功就不显示,那么你需要将设置itemElement为display none,然后将srcBase64的数据读取出来,上传服务器,假如成功设置为显示,否则做提示和删除元素。
        ,onFileItemDelete:function(ListContainer,itemElement,file,srcBase64){

        }//点击删除按钮时候的操作。
    };

    var innerTools={
        getBase4FromImgFile:function(file,callBack){
            console.log("当前的file:");
            console.log(file);
            var reader = new FileReader();
            reader.onload = function(e) {
                var base64Img= e.target.result;
                //var $img = $('<img>').attr("src", e.target.result)
                //$('#preview').empty().append($img)
                if(callBack){
                    callBack(base64Img);
                }
            };
            reader.readAsDataURL(file);
        }
    };
    var app={
        init:function(opts){
            var me=this;
            settings= $.extend({},settings,opts);
            rootEL=$(settings.wrapper);
            me.firstRenderView();

        }
        //--第一次初始化界面。
        ,firstRenderView:function(){
            var _html=tpl_add_button.render({});
            rootEL.empty();
            var el1=$(_html);
            _file_add=el1.find('[ui="add-file"]');
            rootEL.append(el1);
            this.initAddButtonEvents(_file_add);

        }
        ,initAddButtonEvents:function(fileInputElement){
            var me=this;
            fileInputElement.change(function(e){

                if (e.target.files.length === 0) {
                    alert("请选择图片");
                    return; }

                var oFiles = e.target.files;
                //if (!rFilter.test(oFile.type)) { alert("You must select a valid image file!"); return; }

                /*  if(oFile.size>5*1024*1024){
                 message(myCache.par.lang,{cn:"照片上传:文件不能超过5MB!请使用容量更小的照片。",en:"证书上传:文件不能超过100K!"})
                 changePanel("result");
                 return;
                 }*/
                //--没办法,里面是异步的,for循环会先循环一次然后执行异步内容,也就是说,所有的变量最后都会变成最后一个。现在采用队列执行的方式来处理。

                var _queueBusy=false;
                var _queueFinish=false;
                var _currentQueueIndex=0;
                var _vars={};
                var _queueInterval=setInterval(function(){
                    if(_queueBusy==true){
                        return;
                    }
                    if(_queueFinish==true){
                        clearInterval(_queueInterval);
                        return;
                    }
                    if(_currentQueueIndex>=oFiles.length){
                        _queueFinish=true;

                        return;
                    }
                    _queueBusy=true;
                    var _oFile=oFiles[_currentQueueIndex];
                    console.log("现在执行队列:"+_currentQueueIndex);

                    if(!new RegExp("(jpg|jpeg|gif|png)+","gi").test(_oFile.type)){
                        ///alert("照片上传:文件类型必须是JPG、JPEG、PNG或GIF!");
                        _currentQueueIndex++;
                        _queueBusy=false;
                        return;
                    }

                    var i=_currentQueueIndex;
                    _currentQueueIndex++;
                    _vars["oFile"+i]=oFiles[i];
                    _vars["element"+i]=$(tpl_list_item.render({}));
                    _vars["preview"+i]=_vars["element"+i].find('[ui="preview"]');
                    _vars["btn_delete"+i]=_vars["element"+i].find('[ui="btn-delete"]');
                    innerTools.getBase4FromImgFile(_vars["oFile"+i],function(base64imgData){

                        _vars["preview"+i].attr("src",base64imgData);
                        _vars["element"+i].hide();
                        rootEL.append(_vars["element"+i]);
                        var _show_del=settings.showDeleteButton(rootEL,_vars["element"+i],_vars["oFile"+i],base64imgData);
                        if(_show_del==true){
                            _vars["btn_delete"+i].show();
                        }
                        else if(_show_del==false){
                            _vars["btn_delete"].hide();
                        }
                        var _res=settings.onFileHanding(rootEL,_vars["element"+i],_vars["oFile"+i],base64imgData);
                        if(_res==true){
                            _vars["element"+i].show();
                        }
                        else{
                            _vars["element"+i].show();
                        }
                        me.initListElementEvents(_vars["btn_delete"+i],rootEL,_vars["element"+i],_vars["oFile"+i],base64imgData);
                        _queueBusy=false;
                    });

                },20);


                return;

                var _vars={};
                for(var i=0;i< oFiles.length;i++){
                    var oFile=oFiles[i];
                    _vars["oFile"+i]=oFile;
                    console.log("外层loop的index:");
                    console.log(i);
                    if(!new RegExp("(jpg|jpeg|gif|png)+","gi").test(oFile.type)){
                        ///alert("照片上传:文件类型必须是JPG、JPEG、PNG或GIF!");
                        continue;
                    }

                    var _listitemElement=$(tpl_list_item.render({}));
                    _vars["element"+i]=_listitemElement;

                    var _img_preview=_listitemElement.find('[ui="preview"]');
                    _vars["preview"]=_img_preview;
                    var _btn_delete=_listitemElement.find('[ui="btn-delete"]');
                    _vars["btn_delete"]=_btn_delete;

                    innerTools.getBase4FromImgFile(oFile,function(base64imgData){
                        console.log("当前的i:");
                        console.log(i);
                        console.log(oFile);
                        _img_preview.attr("src",base64imgData);
                        _listitemElement.hide();
                        rootEL.append(_listitemElement);
                        var _show_del=settings.showDeleteButton(rootEL,_listitemElement,oFile,base64imgData);
                        if(_show_del==true){
                            _btn_delete.show();
                        }
                        else if(_show_del==false){
                            _btn_delete.hide();
                        }
                        var _res=settings.onFileHanding(rootEL,_listitemElement,oFile,base64imgData);

                        if(_res==true){
                            _listitemElement.show();
                        }
                        else{
                            _listitemElement.hide();
                        }
                        me.initListElementEvents(_btn_delete,rootEL,_listitemElement,oFile,base64imgData);

                    });
                }
            });
        }
        //--初始化每个图片单元的相关事件,譬如,删除,
        ,initListElementEvents:function(btnDelElement,rootEl,itemEl,file,base64ImgData){
            btnDelElement.click(function(){
                //alert("点击了删除按钮。");
                console.log(itemEl);
                settings.onFileItemDelete(rootEl,itemEl,file,base64ImgData);
            });

        }
    };
    module.exports=app;

});



采用的模板如下:

<li class="up-entry"><input class="upfile" type="file" accept="image/*" multiple="" ui="add-file"></li>



    <li class="up-pic up-over" ui="fileitem">
        <div class="clip">
            <img src="http://1diandi.oss-cn-qingdao.aliyuncs.com/2014-12-18/a6809a02164140ddb644f064e300a733.jpg" ui="preview" style="width: 65px; height: 65px; display: block; margin-top: 0px;"></div>
        <div class="up-mask"></div>
        <div class="up-progress">
            <div class="pos" ui="progress-bar" style="-webkit-transition: all 1s ease-out; transition: all 1s ease-out; width: 38px;"></div>
        </div>
        <div class="up-fail">上传失败</div>
        <div class="up-success">上传失败</div>
        <a class="btn-del" href="javascript:void(0)" title="删除图片" ui="btn-delete"><i class="fa fa-times-circle"></i></a>
    </li>


注意,这个组件用在整体的前端环境中,需要有对应的模板,seajs的配置等等。



执行界面:



【前端】关于在for循环里面执行异步脚本导致变量都采用最后的一个变量问题_第1张图片



你可能感兴趣的:(【前端】关于在for循环里面执行异步脚本导致变量都采用最后的一个变量问题)