javascript下使用Promise封装FileReader
Promise在处理异步的时候是个很好的选择,可以减少嵌套层次,让代码更好读,逻辑更清晰。ES6将其加入规范,jQuery3.0也修改实现向规范靠拢(3.0发布公告)。一些新增元素比如.fetch()原生就“thenable”,不过大多数以往的API还要依赖回调,这个时候,我们只要将它们重新封装,就能避开嵌套陷阱,享受Promise带来的愉悦体验。
Promise一般用法
先来看下Promise的一般用法。
//声明Promise对象
varp=newPromise(function(resolve,reject){
//不管啥时候,该执行then了,就调用resolve
setTimeout(function(){
resolve(1);
},5000);
//或者不管啥问题,就调用reject
if(somethingWrong){
reject('2');
}
});
//使用Promise对象
p.then(function(num){
//对应上面的resolve
console.log(num);//1
},function(num){
//对应上面的reject
console.log(num);//2
});
Promise的驱动模型并不复杂:任何操作,假定它只有两个结果,成功或者失败。那么只需要在合适的时间调用合适的程序,进入合适的后续步骤即可。.then()顾名思义,就是下一步的意思,当前面的Promise有了结果——即调用resolve或者reject——之后,就启动对应的处理函数。
Promise实例创建后就会开始执行,判定结果需要我们自己来,比如加载成功,或者满足某个条件,等等。通过串联.then()则可以完成一系列操作。每次调用.then()都会创建一个新的Promise实例,它会静静等待前面的实例状态改变后再开始执行。
封装FileReader
接下来开始封装。思路很简单,FileReader除了提供各种read方法,还有几个事件钩子,其中onerror和onload很明显可以作为判断任务是否完成的依据。加载成功的话,就需要用到文件内容,所以将文件或文件内容传递到下一步也十分必要。
最后完成的代码如下:
functionreader(file,options){
options=options||{};
returnnewPromise(function(resolve,reject){
letreader=newFileReader();
reader.onload=function(){
resolve(reader);
};
reader.onerror=reject;
if(options.accept&&!newRegExp(options.accept).test(file.type)){
reject({
code:1,
msg:'wrongfiletype'
});
}
if(!file.type||/^text\//i.test(file.type)){
reader.readAsText(file);
}else{
reader.readAsDataURL(file);
}
});
}
为了能真正派上用场,里面还有一些验证文件类型的操作,不过跟本文主旨无关,略过不表。这段代码的核心是创建一个Promise对象,等待FileReader读取完成后调用resolve方法,或者出现问题时调用reject方法。
使用刚才封装好的函数
接下来就可以在项目中使用了:
reader(file)
.then(function(reader){
console.log(reader.result);
})
.catch(function(error){
console.log(error);
});
.then()支持两个参数,第一个在Promise成功时启动,第二个自然在失败时启动。用.catch()可以实现同样地效果。Promise的好处除了可读性更佳以外,返回的Promise对象还可以任意传递,继续进行链式调用,有很大想象空间。
继续.then()
于是我们不妨串联更多操作(本来想写个断点续传的,回头再说吧):
全选复制放进笔记reader(file)
.then(function(reader){
returnnewPromise(function(resolve,reject){
//就随便暂停个5秒吧……
setTimeout(function(){
resolve(reader.result);
},5000);
});
})
.then(function(content){
console.log(content);
});
以上就是本文的全部内容,希望对大家的学习有所帮助。