上面了解promise a+之后,那么这篇文章就是扩展一下promise的周边方法
promisify的实现
promisify是node提供的一个方法用来解决回调嵌套问题,用起来很方便;我项目中有两个文件,一个为name.txt,里面存放的是age.txt,另一个为age.txt里面的内容为18,这里就是为了演示多个异步接收返回值问题,现在让我们看看原来获取异步返回值,毫无疑问这样非常的恶心
原始调用异步
let fs= require('fs');fs.readFile('./name.txt', 'utf8', function (err, data) { console.log(data);//age.txt if (err) { console.log(err); } else { fs.readFile(data, 'utf8', function (err, data) { if (err) { console.log(err); } else { console.log(data); } }) }});
既然已经看到他的恶心之处了,那我们想办法优化一下,封装一个公共函数:
read公共方法的封装
function read(...args) { let dfd = Promise.defer();//这个是我们上一账封装的promise中的方法 fs.readFile(...args, function (err, data) { if (err) dfd.reject(err); dfd.resolve(data) }); return dfd.promise}
使用的时候如下:
read('./name.txt', 'utf8').then(data => { console.log(data); return read(data, 'utf8')}).then(data => { console.log(data);})
上面这种看起来不错,但是还是不能让人满意,因为他的功能太单一了,这时候我们的主角promisify就上场了,那么我们先来看一看它原本是怎么用的:
promisify使用
let {promisify} = require('util');//node提供的方法库let readFile = promisify(fs.readFile); //用什么方法就把对应的方法传进去,肥肠的方便readFile('./name.txt', 'utf8').then(data => { console.log(data);//age.txt return readFile(data, 'utf8')}).then(data => { console.log(data);//18})
promisify实现
上面的用法很简单,那么我们简单的实现一下吧,用法和以上相同
function promisify(fn) {//你传进来的方法fs.readFile/fs.writeFile... return function (...args) {//传进来的路径,格式 //既然有then那么他就是一个promise return new Promise((resolve, reject) => { fn(...args,function (err,data) { if(err) reject(err) resolve(data) }) }) }}
promise.all实现
promise.all方法传入一个数组,最后按顺序返回一个数组,如果数组中其中一项为失败那么就是失败态
用法:
Promise.all([1, readFile('./name.txt', 'utf8'), 2, readFile('./age.txt', 'utf8'), 3]).then(data => { console.log(data); //[1,'age.txt'(name中写的内容),2,'18'(age中写的内容),3]});
实现:
//校验传进来的值是不是promise,是返回true,否则返回falsefunction isPromise(x) { if((typeof x==='object'&&x!=null)||typeof x ==='function'){ if(typeof x.then ==='function'){ return true } } return false}Promise.all = function (arr) { //返回一个promise return new Promise((resolve, reject) => { let ary = []; //用来记录返回数组的长度 let idx=0; let insertAry=(value,index)=>{ ary[index]=value; if(++idx===arr.length){ resolve(ary) } }; //循环传入的数组 for (let i = 0; i < arr.length; i++) { let currentValue = arr[i]; if (isPromise(currentValue)) { //如果是promise currentValue.then(y=>{ insertAry(y,i) },reject) } else { //如果是普通值 insertAry(currentValue,i) } } })};
直接调用promise.reslove和promise.reject
用法:
Promise.resolve(1).then(data=>{console.log(data)})
实现:
Promise.resolve=function(value){ return new Promise((resolve,reject)=>{ resolve(value) })};
catch
catch就是一个没有成功参数的then,在上一篇文章封装好的Promise中加入一个catch函数
catch(fn){//catch接收一个函数 return this.then(null,fn)//返回的也是promise }
promise中的finally
不管成功还是失败都会执行,并且返回一个promise以供then调用,也是then的另一种执行形式
用法:
Promise.resolve(readFile('./name.txt','utf8')).then(data=>{ // console.log(data); return data}).catch(err=>{ console.log(err);}).finally(data=>{ console.log('finally');}).then(data=>{ console.log(data);});
实现:
在上篇封装的promise中加入以下方法
finally(callback){
return this.then( res => Promise.resolve(callback()).then(() => res), err => Promise.resolve(callback()).then(() => { throw err; }) )}
promise中的race
用法:
Promise.race([readFile('./name.txt','utf8'),readFile('./age.txt','utf8')]).then(data=>{ console.log(data);});
实现:
Promise.race=function (arr) { return new Promise((resolve,reject)=>{ for (let i = 0; i < arr.length; i++) { let currentValue=arr[i]; //这个isPromise用的是上面promise.all文本块的方法 if(isPromise(currentValue)){ currentValue.then(data=>{ resolve(data) },reject) }else { resolve(currentValue) } } })};