Promise简单学习并使用
一直知道有这个东西,但是并没有使用过,今天简单做个记录。参考文档来源在这里,(如果有侵权,联系我删除哦!)我并没有完全照抄,也在尝试着做自己的归纳总结,不过暂时还没有机会在项目中去使用Promise。
[参考文档]https://www.cnblogs.com/whybxy/p/7645578.html
基本用法
Promise的构造函数接收一个函数作为参数,并且该函数传入两个函数作为参数:resolve,reject,分别表示此次异步操作执行成功后的回调函数和异步操作执行失败后的回调函数。
new Promise((reslove,reject)=>{
setTimeout(()=>{
console.log('bingo1!');
reslove('somedata1')
},2000)
})
// bingo1!
所谓的成功和失败也只是将promise的状态值改变,不过抽象一下即可表示当前操作的执行状态。
函数用法
Promise的常规使用都是封装在一个函数中,在需要使用的时候去运行这个函数。
//使用promise一般都是包含在一个函数中,在需要的时候再去运行这个函数
let Async = () => {
let pro = new Promise((resolve, reject) => {
//一些异步操作
setTimeout(() => {
console.log('bingo2!');
resolve('somedata2!')
}, 2000)
})
return pro
}
//调用
Async()
.then((data)=>{
console.log(data);
})
//bingo2!
在Async函数中,将pro这个Promise实例返回,Promise实例上有then方法,then接收一个函数作为参数,并且会拿到我们在Async中调用resolve时传入的参数。(我个人理解的是一种另类的回调函数形式,将回调函数分离出来执行)
链式操作
个人感觉这个是一种非常好玩的地方,类似于jQuery的这种链式操作,可以将因为各种因素导致异步操作无法预测的这种情况穿成一个珠子这种的形式。
let fn1 = () =>{
let pro = new Promise((resolve,reject)=>{
//异步操作
setTimeout(()=>{
console.log('执行成功1!');
resolve('数据1')
},2000)
})
return pro
}
let fn2 = () =>{
let pro = new Promise((resolve,reject)=>{
//异步操作
setTimeout(()=>{
console.log('执行成功2!');
resolve('数据2')
},2000)
})
return pro
}
let fn3 = () =>{
let pro = new Promise((resolve,reject)=>{
//异步操作
setTimeout(()=>{
console.log('执行成功3!');
resolve('数据3')
},2000)
})
return pro
}
fn1()
.then((data)=>{
console.log('第一次执行接收到的数据:',data);
return fn2()
})
.then((data)=>{
console.log('第二次执行接收到的数据:',data);
return fn3()
})
.then((data)=>{
console.log('第三次执行接收到的数据:',data);
})
/*
执行成功1!
第一次执行接收到的数据: 数据1
执行成功2!
第二次执行接收到的数据: 数据2
执行成功3!
第三次执行接收到的数据: 数据3*/
上面这一连串的链式操作,将3个异步的操作转换成了另类的同步操作,当fn1执行成功后,将fn1内部的promise实例返回,将resolve里面的参数传递给then里面的函数。再返回fn2里面的Promise实例,以此类推。通俗的说就是fn1执行完毕后,成功了就执行fn2,再fn3。在这个例子中,fn函数中返回的不一定是一个Promise实例。也是以是任意类型的数据,但此时后面的函数接收到的参数也就将不再是一个promise对象,而是一个具体的数据。
fn1()
.then((data)=>{
console.log('第一次执行接收到的数据:',data);
return fn2()
})
.then((data)=>{
console.log('第二次执行接收到的数据:',data);
return '直接返回的数据~~~~~~~'
})
.then((data)=>{
console.log('第三次执行接收到的数据:',data);
})
/*
执行成功1!
第一次执行接收到的数据: 数据1
执行成功2!
第二次执行接收到的数据: 数据2
第三次执行接收到的数据: 直接返回的数据~~~~~~~
*/
reject用法
上面大量的使用到了resolve这个函数,可以是我们大家比较预期的都是希望成功,但是事实往往是相反的,哈哈,其实这个函数也有值得注意的地方。
//reject的情况
let getNumber = () => {
let pro = new Promise((resolve,reject)=>{
//一些异步操作
setInterval(()=>{
//生成一个1-10的随机数
let num = Math.ceil(Math.random() * 10)
num < 5 ? resolve ('琪琪今天吃一碗饭') : reject ('琪琪今天吃两碗饭')
},2000)
})
return pro
}
getNumber()
.then(
(resolve)=>{
console.log(resolve);
},
(reject)=>{
console.log('修改Promise状态->rejectde');
console.log(reject);
}
)
/*
琪琪今天吃一碗饭
或者
修改Promise状态->rejectde
琪琪今天吃两碗饭
*/
在这个例子中,在then中传递了两个参数函数分别对应resolve以及reject对应的函数。如果得到的数小于5,对应第一个函数,大于5则对应第二个函数。(注:原文中这里使用的setTimeout函数,我替换成setInterval之后发现其实只会执行一次log函数。虽然计数器会一直跑下去,但却不会再执行then中的函数了。具体我也不知道为什么,我猜测应该和内存被回收有关系。)
cath的用法
cath方法再Promise中也是一个非常好用的函数,通常我们在写js代码的时候,如果遇到错误将会阻塞后续代码的执行,而cath将会捕获异常代码,具有一定的容错率。
getNumber()
.then((data)=>{
console.log(data);
console.log(falseData1);
console.log('此处代码正确执行未阻塞1');
})
.catch((data)=>{
//console.log(falseData2);
console.log(data);
console.log('此处代码正确执行未阻塞2');
})
//falseData1 未定义,进入到cath中执行cath的语句,错误信息作为参数传递给cath
//falseData2未定义,若直接进入cath 则直接报错
//-> 也就是说,cath将捕获程序的异常。但同时并不影响自身执行
由于falseData1是我输入的错误代码,执行到这里的时候会直接将错误信息作为参数传递给cath中,并且执行cath中的语句,而后续的console.log(‘此处代码正确执行未阻塞1’);此条语句并不会执行。但是这里有一个有意思的地方,就是当上面的判断也就是数字大于5后,也将会执行cath里面的语句,将执行错误的Promise对象作为参数传递给cath。所以我的总结就是,cath能够捕获程序的异常并且本身也能作为reject所对应的函数所使用。
all race 的用法
这个函数类似于,小朋友,分瓜瓜,排排坐的形式。将所有的异步操作状态都确定后才会执行后续的代码(比较经典的应用场景也就是静态资源的统一加载吧)
//all的用法
let fn1 = () =>{
let pro = new Promise((resolve,reject)=>{
//异步操作
setTimeout(()=>{
console.log('执行成功1!');
resolve('数据1')
},1000)
})
return pro
}
let fn2 = () =>{
let pro = new Promise((resolve,reject)=>{
//异步操作
setTimeout(()=>{
console.log('执行成功2!');
resolve('数据2')
},2000)
})
return pro
}
let fn3 = () =>{
let pro = new Promise((resolve,reject)=>{
//异步操作
setTimeout(()=>{
console.log('执行成功3!');
resolve('数据3')
},3000)
})
return pro
}
Promise.all(
[fn1(),fn2(),fn3()]
)
.then((data)=>{
console.log(data);
})
/*
执行成功1!
执行成功2!
执行成功3!
['数据1','数据2','数据3']
*/
通过控制台明显的观察到,最后的log函数是在fn3中的定时器执行之后才执行的,也就是说all方法是以响应得最慢的操作作为基准,当然,看到了这个最慢的肯定就有以最快的操作作为基准的了,就是race方法。
Promise.race(
[fn1(),fn2(),fn3()]
)
.then((data)=>{
console.log(data);
})
/*
执行成功1!
数据1
执行成功2!
执行成功3!
*/
最后: 花了差不多两个小时的时间把Promise的用法看了一下,简单理解了一下他的使用方法。今后会有意识的在项目中去使用Promise,感觉比回调函数好用一些。