从使用事件对象的嵌套FileReader onload函数进行回调

问题描述:

我几乎没有理论,但正在陷入精细的细节。给定变量$data(它是更改后文件输入的event object)的图像大小调整功能将返回一个变量dataurl(这是一个dataurljpeg)。从使用事件对象的嵌套FileReader onload函数进行回调

我的问题是得到dataurl承认它是嵌套函数内更新。下面显示的代码正在将data:image/jpg;base64记录到控制台,显示dataurl未更新。

研究使我发现,这是由于异步调用,这是有道理的。在继续并打印到控制台之前,var并未及时更改。我还了解到,这是发布callback来更新变种的标准情况。

经过一番尝试,我无法找到一个干净的(或工作)方法来使用callback更新var。

function clProcessImages($data) { 

     var filesToUpload = $data.target.files; 
     var file = filesToUpload[0]; 
     var canvas = document.createElement('canvas'); 
     var dataurl = 'data:image/jpg;base64'; 

     var img = document.createElement("img"); 

     var reader = new FileReader(); 
     reader.onload = function(e, callback) { 

      img.onload = function() { 

       var ctx = canvas.getContext("2d"); 
       ctx.drawImage(img, 0, 0); 

       var MAX_WIDTH = 800; 
       var MAX_HEIGHT = 600; 
       var width = img.width; 
       var height = img.height; 

       if (width > height) { 
        if (width > MAX_WIDTH) { 
         height *= MAX_WIDTH/width; 
         width = MAX_WIDTH; 
        } 
       } else { 
        if (height > MAX_HEIGHT) { 
         width *= MAX_HEIGHT/height; 
         height = MAX_HEIGHT; 
        } 
       } 
       canvas.width = width; 
       canvas.height = height; 
       var ctx = canvas.getContext("2d"); 
       ctx.drawImage(img, 0, 0, width, height); 
       dataurl = canvas.toDataURL("image/jpeg",0.8); 
       callback(dataurl); 

      } 
      img.src = e.target.result 

     } 
     reader.readAsDataURL(file); 

     console.log(dataurl); // console log mentioned in question 
     return dataurl; 

    }; 

这是代码,因为它主张,在解决如何拉断callback的中间位置:当我表明我当前的代码,我会扩大这一点。我知道在它显示的状态下,回调不会被调用。

我的第一个障碍是,我(似乎)不能稍后再打电话了reader.onload功能,因为它似乎是专门当对象被加载事件被触发的,不是随时手动调用上。我最好的猜测是创建一个新的函数,它会触发,将包含所有当前的函数,并且我可以稍后指定,发出callback,跳过参考onload事件。

看起来像一个合理的理论,但后来我陷入了event objectonload函数通过。假设我应用了上述理论,并且onload事件调用了新函数readerOnLoad(e)。它会通过event object罚款。但是,如果稍后想要执行回叫,我怎么能手动拨打readerOnLoad(e),因为我看不到以相同的FileReader以优雅的方式传递event object的方法。感觉有点像我为了解决非常混乱的代码*而感觉有点像应该有一些更优雅的东西,而这种情况并不感觉太狭隘。

*原始$dataevent object变量是通过在文件输入检测到变化时存储全局变量而获得的。理论上,我可以创建一个全局变量来存储event objectFileReader onload。它只是感觉相当复杂,因为我的原始代码和以这种方式运行的代码之间的区别是非常严重和不合适的,因为唯一的区别是更新了未及时准备好的var。

使用异步函数时,通常需要传递一个函数作为回调函数。您可以使用的NodeJS风格的回调是这样的:

// asyncTask is an asynchronous function that takes 3 arguments, the last one being a callback 

asyncTask(arg1, arg2, function(err, result) { 
    if (err) return handleError(err); 
    handleResult(result); 
}) 

所以你的情况,你可以这样做:

clProcessImages($data, function(dataurl) { 
    console.log(dataurl); 
    // Do you other thing here 
}); 

function clProcessImages($data, onProcessedCallback) { 
    var filesToUpload = $data.target.files; 
    var file = filesToUpload[0]; 
    var canvas = document.createElement('canvas'); 
    var dataurl = 'data:image/jpg;base64'; 

    var img = document.createElement("img"); 

    var reader = new FileReader(); 
    reader.onload = function(e) { 

    img.onload = function() { 

     var ctx = canvas.getContext("2d"); 
     ctx.drawImage(img, 0, 0); 

     var MAX_WIDTH = 800; 
     var MAX_HEIGHT = 600; 
     var width = img.width; 
     var height = img.height; 

     if (width > height) { 
     if (width > MAX_WIDTH) { 
      height *= MAX_WIDTH/width; 
      width = MAX_WIDTH; 
     } 
     } else { 
     if (height > MAX_HEIGHT) { 
      width *= MAX_HEIGHT/height; 
      height = MAX_HEIGHT; 
     } 
     } 
     canvas.width = width; 
     canvas.height = height; 
     var ctx = canvas.getContext("2d"); 
     ctx.drawImage(img, 0, 0, width, height); 
     dataurl = canvas.toDataURL("image/jpeg",0.8); 
     onProcessedCallback(dataurl); 

    } 
    img.src = e.target.result 

    } 
    reader.readAsDataURL(file); 

    return dataurl; 
}; 

您可能还需要错误对象传递给回调像第一个例子,并妥善处理。

总之,总是添加一个回调函数作为您自己的异步函数的参数。

+0

效果很好,解释有意义。感谢那。其中一个特点是,如果我在'console.log'后立即添加'form_data.append('file',dataurl);'(确认它已正确更新以包含jpeg),我的PHP处理程序说它是空的if我检查'if(!file_exists($ _ FILES ['file'] ['tmp_name'])||!is_uploaded_file($ _ FILES ['file'] ['tmp_name']))'。尽管我附加到'form_data'的所有内容在处理程序中都可以正常返回,但建议表单发送正常。 – biscuitstack

+0

想想我明白了。当我按照以下方式将dataurl转换为blob时工作:http://stackoverflow.com/questions/4998908/convert-data-uri-to-file-then-append-to-formdata/5100158。不知道为什么许多帖子在这个网站的其他地方建议追加dataurl照原样。 – biscuitstack