Node.js实现兼容IE789的文件上传进度条


Posted in Javascript onSeptember 02, 2016

Nodejs对文件上传的处理

在Express4里req.files已经是undefined了;现在用的最多的可能就是formidable了,你知道了它有个progress事件,于是心中大喜,低版本IE的进度条有戏了;OK,试一下:

form 
 .on('error',function(err){ 
  console.log(err);
 }) 
 .on('aborted',function(){ 
  console.log('aborted'); 
 })
 .on('progress',function(bytesReceived, bytesExpected){ 
  var n=parseInt(parseFloat(bytesReceived/bytesExpected).toFixed(2)*100); 
  console.log(n); 
 });

是的,你很高兴的看到了,控制台按照预期打印了一串进度值;那么,再进一步;

form 
 .on('progress',function(bytesReceived, bytesExpected){ 
  var n=parseInt(parseFloat(bytesReceived/bytesExpected).toFixed(2)*100); 
  res.write('<script>window.parent.call('+n+')</script>'); 
  //无刷新上传,你们懂的 console.log(n); 
 });

call方法即在页面上显示进度值;很不幸,你只能看到最后的100%,看不到上传具体详细的进度值;再探...

接下来换个思路,试一下,将进度值保存到session里,额外加一个请求来轮询这个进度值,哎哟,不错哦!为了保证你请求的进度值是你这次上传的进度值而不是其他上传的进度值,需要在上传的请求里和额外的请求里约定一个token值;现在又来一个问题就是怎么在请求的时候得到这个token,由于文件上传的请求体在Request Payload里,所以req.body拿不到带过去的值,我也不想去解析这堆了,当然我也解析不了;放在url里最好,问题在于有时候得刷新两次来刷新token,不好!不得已,我还是放在cookie里吧!

var cookies=function () { 
  var cks=req.headers.cookie.split(';'),obj={}; 
  for(var i=0;i<cks.length;i++){ 
   obj[cks[i].split('=')[0].replace(/\s+/ig,'')]=unescape(cks[i].split('=')[1]); 
  } 
  return obj; 
 }(); 
 var queryToken=cookies.__token__;
 
 form .on('progress',function(bytesReceived, bytesExpected){ 
  var n=parseInt(parseFloat(form.bytesReceived/form.bytesExpected).toFixed(2)*100); 
  if (req.session['file'+queryToken]) {  
   req.session['file'+queryToken].percent=n; 
  }else{ 
   req.session['file'+queryToken]={ 
    token:queryToken, 
    percent:n 
   } 
  }; 
  console.log(n); 
 });

为了IE789,我来轮询进度值了,原谅我,其实我的心很痛;

var getData=function(){ 
  $.post('/uploader',{ 
   getfileinfo:1, 
   uploadtoken:utils.cookie.getCookie('__token__') 
  })
  .then(function(data){ 
   console.log(data);
   if (data.mes<0) { 
    getData(); 
   }else{ 
    var pros=data.info; 
    call(pros.percent);
    if (pros.percent!='100') { 
     getData(); 
    }; 
   }; 
  }); 
 } 
 getData();

call方法即在页面上显示进度值;很不幸,你只能看到最后的100%,看不到上传具体详细的进度值;再探...

好吧,我又一次沦陷了;不过还是感觉不对劲,ajax轮询没有问题,问题在于session里要等到上传完毕才有值,所以只能看到100%,看不到详细进度值;我是否可以认为,在progress里,之前的res.write和这次的req.session被挂起了呢,但是它又保存了每次的执行结果,直到progress完再释放,所以只能看到100%;没心情看formidable的源码,当然我也看不咋懂,我就先这么认为吧!

既然ajax轮询没问题,那么就是保存到session不得劲了;实在不成,放到global里试试吧,总不会往全局对象里塞个值也会挂起吧;稍作改动放到global里:

form 
 .on('progress',function(bytesReceived, bytesExpected){ 
  var n=parseInt(parseFloat(form.bytesReceived/form.bytesExpected).toFixed(2)*100);
  if (global['file'+queryToken]) { 
   global['file'+queryToken].percent=n; 
  }else{ 
   global['file'+queryToken]={ 
    token:queryToken, 
    percent:n 
   } 
  }; 
  console.log(n); 
 });

继续轮询。

漂亮,完全就是那么回事!在chrome里看到的和HTML5的进度一个效果,只是在IE789里会有点卡顿的感觉,不过还是能看到详细的进度值的;毕竟老浏览器身子骨不咋地,你们懂的;还有,每次上传都往global里塞值,怎么也得适当的清理一下吧,文件上传完毕,转移到指定目录后global['file'+queryToken]=null

然而,轮询,就是一个接一个好多好多的请求,这里也许会出问题;要不限制一下吧,间隔500ms请求一次进度值;恩,IE789进度条就这么解决了,说好的丢掉flash;虽然这个轮询可以兼容所有浏览器,但毕竟要浪费那么多请求,还是判断下,在IE789以外继续HTML5吧!

其实衡量一下,额外加个flash上传和额外的请求,哪个更值呢,原谅我不懂flash,就不多说了,反正我很不喜欢在页面上加一下额外的文件;

总结

关于文件上传的组件,还有很多的细节处理,本想弄一个JS文件的,后来一想,为了可复用性更强,还是作为一个独立的页面搞比较好,需要上传的地方,iframe一下就行了,肯定比弄一个JS文件要好很多。以上就是这篇文章的全部内容,希望能够对大家的学习或者工作带来一定的帮助,如果有疑问大家可以留言交流。

Javascript 相关文章推荐
JavaScript 常用函数
Dec 30 Javascript
文本框只能选择数据到文本框禁止手动输入
Nov 22 Javascript
分享纯手写漂亮的表单验证
Nov 19 Javascript
js css3实现图片拖拽效果
Mar 04 Javascript
jQuery实现div跟随鼠标移动
Aug 20 jQuery
详谈js对url进行编码和解码(三种方式的区别)
Aug 16 Javascript
JS分页的实现(同步与异步)
Sep 16 Javascript
vue使用自定义icon图标的方法
May 14 Javascript
Vue路由切换时的左滑和右滑效果示例
May 29 Javascript
详解Angular操作cookies方法
Jun 01 Javascript
解决使用layui对select append元素无效或者未及时更新的问题
Sep 18 Javascript
javascript+Canvas实现画板功能
Jun 23 Javascript
AngularJs  Understanding Angular Templates
Sep 02 #Javascript
jquery 中toggle的2种用法详解(推荐)
Sep 02 #Javascript
浅谈JS中的三种字符串连接方式及其性能比较
Sep 02 #Javascript
AngularJs  E2E Testing 详解
Sep 02 #Javascript
解决node.js安装包失败的几种方法
Sep 02 #Javascript
js两种拼接字符串的简单方法(必看)
Sep 02 #Javascript
AngularJs Understanding the Controller Component
Sep 02 #Javascript
You might like
用PHP伪造referer突破网盘禁止外连的代码
2008/06/15 PHP
PHP把数字转成人民币大写的函数分享
2014/06/30 PHP
php生成随机数的三种方法
2014/09/10 PHP
PHP学习笔记(三):数据类型转换与常量介绍
2015/04/17 PHP
利用Laravel事件系统如何实现登录日志的记录详解
2017/05/20 PHP
PHP pthreads v3下的Volatile简介与使用方法示例
2020/02/21 PHP
JavaScript基本对象
2007/01/11 Javascript
使用新的消息弹出框blackbirdjs
2008/10/16 Javascript
JavaScript游戏之优化篇
2010/11/08 Javascript
jquery 插件学习(二)
2012/08/06 Javascript
自己写的Javascript计算时间差函数
2013/10/28 Javascript
IE下双击checkbox反应延迟问题的解决方法
2014/03/27 Javascript
jQuery插件实现带圆点的焦点图片轮播切换
2016/01/18 Javascript
jQuery form插件的使用之处理server返回的JSON, XML,HTML数据
2016/01/26 Javascript
动态的9*9乘法表效果的实现代码
2016/05/16 Javascript
JS实现针对给定时间的倒计时功能示例
2017/04/11 Javascript
使用JS实现图片轮播的实例(前后首尾相接)
2017/09/21 Javascript
Vue 去除路径中的#号
2018/04/19 Javascript
jQuery事件blur()方法的使用实例讲解
2019/03/30 jQuery
javascript实现前端成语点击验证优化
2020/06/24 Javascript
Python实现基于HTTP文件传输实例
2014/11/08 Python
Python六大开源框架对比
2015/10/19 Python
Sanic框架异常处理与中间件操作实例分析
2018/07/16 Python
python实现图片彩色转化为素描
2019/01/15 Python
python中的句柄操作的方法示例
2019/06/20 Python
如何通过50行Python代码获取公众号全部文章
2019/07/12 Python
Python读写文件模式和文件对象方法实例详解
2019/09/17 Python
解决python虚拟环境切换无效的问题
2020/04/30 Python
Python如何实现线程间通信
2020/07/30 Python
PHP如何删除一个Cookie值
2012/11/15 面试题
购房意向书
2014/04/01 职场文书
电子银行业务授权委托书
2014/10/10 职场文书
单位综合评价意见
2015/06/05 职场文书
SpringBoot连接MySQL获取数据写后端接口的操作方法
2021/11/02 MySQL
JavaScript实现优先级队列
2021/12/06 Javascript
「魔法少女伊莉雅」美游粘土人开订
2022/03/21 日漫