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类和继承 this属性使用说明
Sep 03 Javascript
javascript 延迟加载技术(lazyload)简单实现
Jan 17 Javascript
基于jquery的放大镜效果
May 30 Javascript
JS实现控制表格单元格垂直对齐的方法
Mar 30 Javascript
在javascript中随机数 math random如何生成指定范围数值的随机数
Oct 21 Javascript
使用json来定义函数,在里面可以定义多个函数的实现方法
Oct 28 Javascript
JavaScript定时器实现的原理分析
Dec 06 Javascript
JS基于onclick事件实现单个按钮的编辑与保存功能示例
Feb 13 Javascript
Angular2学习教程之ng中变更检测问题详解
May 28 Javascript
AngularJS ui-router刷新子页面路由的方法
Jul 23 Javascript
原生js实现随机点名
Jul 05 Javascript
vue3+typescript实现图片懒加载插件
Oct 26 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的正则处理函数总结分析
2008/06/20 PHP
php 验证码实例代码
2010/06/01 PHP
解析thinkphp基本配置 convention.php
2013/06/18 PHP
ThinkPHP中session函数详解
2016/09/14 PHP
php 猴子摘桃的算法
2017/06/20 PHP
PHP大文件分片上传的实现方法
2018/10/28 PHP
js下写一个事件队列操作函数
2010/07/19 Javascript
javaScript基础语法介绍
2015/02/28 Javascript
js中for in语句的用法讲解
2015/04/24 Javascript
详解jQuery中的元素的属性和相关操作
2015/08/14 Javascript
Bootstrap中CSS的使用方法
2016/02/17 Javascript
node.js调用Chrome浏览器打开链接地址的方法
2017/05/17 Javascript
jquery实现选项卡切换代码实例
2019/05/14 jQuery
layui点击弹框页面 表单请求的方法
2019/09/21 Javascript
微信小程序 导入图标实现过程详解
2019/10/11 Javascript
Vue实现base64编码图片间的切换功能
2019/12/04 Javascript
ES5 模拟 ES6 的 Symbol 实现私有成员功能示例
2020/05/06 Javascript
Node.js API详解之 util模块用法实例分析
2020/05/09 Javascript
jQuery实现倒计时功能完整示例
2020/06/01 jQuery
vue使用canvas实现移动端手写签名
2020/09/22 Javascript
Vue双向数据绑定(MVVM)的原理
2020/10/03 Javascript
[54:53]2014 DOTA2国际邀请赛中国区预选赛 LGD-GAMING VS CIS 第二场
2014/05/23 DOTA
python GUI实例学习
2017/11/21 Python
matplotlib绘制动画代码示例
2018/01/02 Python
python编程培训 python培训靠谱吗
2018/01/17 Python
python提取包含关键字的整行数据方法
2018/12/11 Python
Python 实现域名解析为ip的方法
2019/02/14 Python
基于Tensorflow一维卷积用法详解
2020/05/22 Python
python实现双人五子棋(终端版)
2020/12/30 Python
selenium设置浏览器为headless无头模式(Chrome和Firefox)
2021/01/08 Python
css3 transform过渡抖动问题解决
2020/10/23 HTML / CSS
韩国三星集团旗下时尚品牌官网:SSF SHOP
2016/08/02 全球购物
珍惜水资源建议书
2014/03/12 职场文书
校庆活动策划方案
2014/06/05 职场文书
小组口号大全
2014/06/09 职场文书
python之json文件转xml文件案例讲解
2021/08/07 Python