Promise的理解及react中的运用
前言
前几天同事无意间问我对promise的理解,作为一年前端开发的我,虽然项目里一直有在用,但细细回想promise是什么、怎么用的和我对这个的理解,还真不说不出来,所以我周末就好好花了时间对promise进行了浅层的了解,如果有说错的欢迎指点。
一、promise是什么?为什么会有promise?
首先,promise是js的抽象异步处理对象实现异步编程的方案,简单的说就是解决传统js运行单线程的诟病以及异步操作的多层级嵌套带来的麻烦。
Q:资料说promise是个容器,我对这个理解不是很清晰。
我的理解是说,这个容器指promise的异步操作内容,然后我们这个操作放在这个容器里面让他自己执行,不会受外界影响。
然后,promise有三种状态,分别是:pending、fulfilled、rejected;
当 promise执行resolve是状态由pending->fulfilled;
当 promise执行reject是状态由pending->rejected;
状态一旦改变就不会再变。
二、基本用法
1、实例
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
Promise对象是一个构造函数,实例后的Promise是一个对象,该构造函数接受一个函数参数,这个函数参数传入两个参数(resolve,reject), 这两个参数是各是一个函数方法;
我们可以根据函数的结果来判断执行resolve或reject;
2、.then()
promise.then(()=>{
/* resolve 的执行内容 */
},()=>{
/*reject执行的内容*/
.then()方法接受两个函数参数,第一个参数是获取resolve的内容来执行异步操作,第二个参数是执行reject,然后执行一个捕获错误的内容,貌似可以获取代码执行错误的位置;
(我的理解:有then方法的promise才是完整的。)
2.1、第一个函数接受一个来自promise的构造函数resolve传递的对象;
3.2、第二个函数会不会promise构造函数的错误;
注意:建议是不推荐 .then(()=>{},()=>{/ 捕获错误 /}) 这样去捕获错误,而是推荐用.catch的方法去捕获错误 .then(()=>{/ resolve 内容 /}).catch(error){/ error捕获错误 /}。因为直接在后面点catch()就能够捕获第一次发生错误的地方。
运用promise做多层次的回调
终取到这个节点,但是如果用promise就能够同步异步操作去获取到;
console.log('start');
var promise1 = new Promise((resolve,reject)=>{
setTimeout(resolve('葡萄'),1);
promise1.then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',苹果'),1)))
.then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',橘子'),1)))
.then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',香蕉'),1)))
.then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',西瓜'),1)))
.then(value=>{console.log(value)});
console.log('上面是个异步过程,所以我先出来,后面才是水果');
控制台打印:
start
上面是个异步过程,所以我先出来,后面才是水果
葡萄,苹果,橘子,香蕉,西瓜
这里的then都只执行了成功(resolve)方法,来把前面的只拼接起来传给下个then()方法去接受,下个then的value接受到上面的值继续new Promise 来执行下一个异步操作;
3、.all()
Promise.all() 接收一个 promise对象的数组作为参数,当这个数组里的所有promise对象全部变为resolve或reject状态的时候,它才会去调用 .then() 方法。
// `delay`毫秒后执行resolve
function timerPromisefy(delay) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(delay);
}, delay);
var startDate = Date.now();
// 所有promise变为resolve后程序退出
Promise.all([
timerPromisefy(1),
timerPromisefy(32),
timerPromisefy(64),
timerPromisefy(128)
]).then(function (values) {
console.log(Date.now() - startDate + 'ms');
// 約128ms
console.log(values); // [1,32,64,128]
所以,promise.all,会在所有的参数里的Promise方法执行完再返回所有数据,以数组的格式。
4、.race()
Promise.race()的参数跟all一样是接受一个promise对象数组,不同的是race(),的结果是只要有一个promise变个fulfilled或rejected就能够then()中获取值,然后其他的Promise对象则会继续执行。
// `delay`毫秒后执行resolve
function timerPromisefy(delay) {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(delay)
resolve(delay);
}, delay);
// 任何一个promise变为resolve或reject 的话程序就停止运行
Promise.race([
timerPromisefy(1),
timerPromisefy(32),
timerPromisefy(64),
timerPromisefy(128)
]).then(function (value) {
console.log('then',value); // => 1
then,1
三、在react中的运用
1、生命周期的运用
前几天有个需求是要在初次渲染完后获取页面的某个节点,但是我用了reactd的生命周期函数始终取到这个节点,但是如果用promise就能够同步异步操作去获取到;
componentWillMount() {
let P = new Promise((resolve, reject)=>{
console.log('new success')
console.log('promiseNew',document.getElementById('text'))
resolve('8888');
P.then((value)=>{
console.log('then','obj',document.getElementById('text'));
.catch((error)=>{
console.log('it is error',error)
componentDidMount(){
this.setState({isFind:true})
console.log('DidMount',document.getElementById("text"))
render() {
return (
{this.state.isFind ? (<Divider id="text">this is PromiseClick</Divider>) : null}
控制台打印内容:
new success
promiseNew null
DidMount null
then obj <div class="ant-divider ant-divider-horizontal ant-divider-with-text" id="text">…</div>
所以,我的认为是在react的生命周期函数里去执行promise的异步操作,相当于页面加载完再去执行的操作;
2、结合ajax请求的运用
前段时间,刚好有对登录调整的需求,这边登录会请求多个接口(用户信息、token、权限列表),所以之前就是用的多层的函数嵌套,在代码的排查上确实显得不那么直观,所以借此机会用了promise去做了一次代码重构。
一开是我以为NEW一个Promise实例出来,然后用return去传递返回的来的数据就可以了,如下:
错误示范
let P = new Promise((resolve, reject)=>{
request.post(url, { form: reqBody, timeout: configObject.agTimeout }, function (error, response, body){
if(!error) {
resolve(body);
} else {
reject(error);
P.then(result=>{
request.post(list.url1, { form: list.formData, timeout: configObject.agTimeout }, function (error, response, body) {
if(!error){
return body;//用return去传递返回的数据
}else
p.then(newResult => {
console.log('newResult',newResult)
控制台打印内容:newResult ,undefined
原因
Promise异步加载,所以中间的那个ajax请求还没结束时,就会跑到.then里面。
其实,我之前也发现别人代码里每次请求都会重新去new一个Promise然后在构造函数里面去请求ajax,之前觉得这好麻烦,但经过这次实验,算是知道原因了,只有每次请求都去new一个Promise来请求,才能让逻辑按我们所想要的顺序去执行,同时每次请求可以判断成功与否,不成功只要把error传进reject中,就能够在最后面的catch中一起捕获。代码如下:
let P = new Promise((resolve, reject)=>{
$.ajax({
type:"get",
url:"index.aspx",
success:function(data){
if(data.code=="0"){
resolve(data.ResultJson)//在异步操作成功时调用
}else{
reject(data.ErrMsg);//在异步操作失败时调用
P.then(result=>{
return new Promise((resolve,reject) => {
$.ajax({
type:"get",
url:"index.aspx2",
success:function(data){
if(data.code=="0"){
resolve(data.ResultJson)//在异步操作成功时调用
}else{
reject(data.ErrMsg);//在异步操作失败时调用
}).then((result) => {
console.log('result',result)
}).catch((errot)=>{
console.log('error',error)
控制台打印内容: