选择文件,设置图像和上传,而不阻塞用户界面
Posted
技术标签:
【中文标题】选择文件,设置图像和上传,而不阻塞用户界面【英文标题】:Choose file, set image and upload without blocking UI 【发布时间】:2014-06-06 19:11:50 【问题描述】:问题
我可以成功完成以下步骤,但 UI 可能对 2 MB 或更大的文件无响应。这些文件的大小在用户可能从他们的相机或桌面上传的范围内,所以我需要处理它们。
用户使用标准文件输入 html 元素上传文件:
<input class="cancel" type="file" name="userFile" id="userFile" accept="image/*"/>
在客户端,我调整文件大小,使宽度为 500 像素或更小(特别是为了减小大文件的图像大小)并显示图像。
在客户端,我上传了调整大小的较小文件。
演示
请参阅 this fiddle。
您可以看到-
在上传较大的文件时停止移动。 Chrome 中的延迟似乎比 Firefox 更大,但在 Firefox 上仍然很明显。
阻塞原因
在img src 上设置文件数据URL 时。这是必需的,以便可以在画布中调整图像的大小。
img.src = e.target.result;//blocking here
当 img 被写入画布时。这是调整图像大小所必需的。
ctx.drawImage( img, 0, 0, width, height );//blocking here
我考虑过的选项
在 Web Worker 中执行阻止操作。这是不可能的,因为 Web Worker 无法操作 DOM 元素,并且在操作 DOM 时都会发生阻塞调用。
在 Web Worker 中调整原始图像数据的大小。不幸的是,我不知道 img 的格式是什么,因此调整大小需要处理所有图像类型。我不知道有任何 javascript 库可以做到这一点,我也不想编写自己的跨格式图像压缩库。
直接调整img大小,但这不会改变需要上传的底层数据大小。
在服务器上调整大小不是一种选择,因为我想减小上传大小。在客户端调整大小也更好,因为大图像的内存被提前释放并且调整大小的图像立即显示。
其他想法
我知道设置img src是异步的,所以我猜是数据的复制导致了阻塞。我想知道是否有一种方法可以共享相同的数据而不是复制?
我正在使用我认为是使用 FileReader
获取数据 URL,然后将数据 URL 设置为 img.src
和 canvas.drawImage
的标准方法来调整大小(有很多这样的例子,一个是here)。任何有助于提高这种方法或另一种方法的响应能力的帮助将不胜感激。
【问题讨论】:
【参考方案1】:我假设你正在尝试做的是以下
-
用户上传图片
客户端向用户显示质量降低的图像。
然后,客户端会将质量降低的图像上传到您的服务器以供以后使用。
您遇到的问题是您强制 javascript(客户端)执行最有可能在服务器端完成的事情。至于以较低的分辨率显示图像,使用drawImage 可以轻松实现。没有理由立即在客户端向用户显示实际缩减的文件。这是我的使用流程版本。
-
用户上传图片。
客户端将其上传到服务器,同时使用 drawImage 显示降低分辨率的版本。
服务器运行一个类似于one 的脚本,将其调整为请求的大小。
然后,当将来需要使用该图像时,服务器会提供调整大小的版本。
希望对你有帮助!!!
【讨论】:
谢谢,但是 drawImage 是阻塞的原因(“参见阻塞原因”第 2 点)。这不仅用于调整大小,还用于创建合成图像。这样做客户端的好处是减少了服务器上的负载,一些图像甚至可能不会上传到服务器。问题是浏览器似乎在 UI 线程上执行操作,而这些操作最好在工作线程上完成。 如果文件太大以至于它们会减慢主线程的速度,那么这些文件就太大了,因为我从未遇到过这个问题,当你说阻塞时,我假设你的意思是它变慢了。您将无法通过网络工作者运行此操作,因为这样做需要您使用 getDATAURL,这将被浏览器安全软件阻止。你能用这段代码的大致用法和你正在处理的文件的大小来更新你的问题吗? 我的问题的第一句话已经有代码的大小(2MB+)。 getDataUrl 在主线程上很好,而是 src 的大小调整和分配应该在单独的工作人员(尽管目前不可能)上完成,最好由浏览器完成。查看 firefox 源代码,这似乎是事情的工作方式,没有好的 javascript 图像压缩库,我只能暂时接受它。以上是关于选择文件,设置图像和上传,而不阻塞用户界面的主要内容,如果未能解决你的问题,请参考以下文章