ECMAScript笔记——Promise

Promise 概述

  • Promise是ES6中提供的优化异步操作的解决方案。解决了ES6之前异步操作,反复嵌套回调函数所导致的回调地狱问题。
  • 从语法上来讲,Promise是一个构造函数,它可以获取异步操作的请求,且返回一个结果。Promise有三种状态:pending(等待),fulfiled(成功),rejected(失败)。状态一旦改变,就不会再变。创造Promise实例后,它会立即执行

什么是回调地狱

在开发中,会遇到一个异步请求后再执行另一个异步请求的情况。例如请求一个列表数据,之后根据列表找到索引,再去请求分类…一直请求,每一次异步请求,都需要反复嵌套回调函数,导致代码可读性大大降低,后期难以维护。

创建Promise实例

  • 创建一个Promise对象。
  • 调用then()catch()去处理结果。
let fullPromise = new Promise((resolve,reject) => {
	if (true) {
		resolve('Success Promise');
	} else {
		reject('Error Promise');
	}
})

console.log(fullPromise);

fullPromise.then((res) => {
        console.log('resolved',res);
    },(err) => {
        console.log('rejected',err);
    }
)

fullPromise.catch((res) => {
	console.log(res);
})

创建成功的Promise对象——简写resolve

let p = Promise.resolve('Success Promise');

创建失败的Promise对象——简写reject

let p = Promise.reject('Error Promise');

Resolve(),Reject()

  • Promise对象是由关键字new及其构造函数来创建的,构建函数后,会把一个叫做“处理器函数”(executor function)的函数作为它的参数,并且传入两个参数:resolvereject,当异步任务顺利完成返回结果时,会调用resolve,而当异步任务失败返回结果时(通常是一个错误对象),会调用reject
  • 其实这里用“成功”和“失败”来描述并不准确,按照标准来讲,resolve是将Promise的状态置为fullfiledreject是将Promise的状态置为rejected
let fullPromise = new Promise((resolve,reject) => {
	if (true) {
		resolve('Success Promise');
	} else {
		reject('Error Promise');
	}
})

console.log(fullPromise);

这里if设置为true,也就是输出resolve('Success Promise')

打印结果:
在这里插入图片描述
if设置为false,也就是输出reject('Error Promise')

let fullPromise = new Promise((resolve,reject) => {
	if (false) {
		resolve('Success Promise');
	} else {
		reject('Error Promise');
	}
})

console.log(fullPromise);

打印结果:
在这里插入图片描述
可以看到,通过调用resolve()reject()改变了Promise对象的状态。

Then()的用法

  • then()是定义在原型上的 Promise.prototype 。
  • then()之后会返回一个新的promise对象。
  • then()中可以传入两个参数,是函数。第一个对应resolve的回调,第二个对应reject的回调。
let fullPromise = new Promise((resolve,reject) => {
	if (true) {
		resolve('Success Promise');
	} else {
		reject('Error Promise');
	}
})

console.log(fullPromise);

fullPromise.then((res) => {
        console.log('resolved',res);
    },(err) => {
        console.log('rejected',err);
    }
)

打印结果:
在这里插入图片描述
可以看到then()对应resolve()获取到了结果res

if设置为false:

let fullPromise = new Promise((resolve,reject) => {
	if (false) {
		resolve('Success Promise');
	} else {
		reject('Error Promise');
	}
})

console.log(fullPromise);

fullPromise.then((res) => {
        console.log('resolved',res);
    },(err) => {
        console.log('rejected',err);
    }
)

打印结果:
在这里插入图片描述
可以看到then()对应reject()获取到了结果err

通过then()就能把原来的回调写法分离出来,在异步操作执行完后,用链式调用的方式执行回调函数。

链式操作的用法

  • 从表面上看,Promise只是能够简化层层回调的写法,而实质上,Promise的精髓是“状态”,用维护状态、传递状态的方式来使得回调函数能够及时调用,它比传递callback函数要简单、灵活的多。
  • 可以在then()中继续写Promise对象并返回,然后继续调用then()来进行回调操作。

所以使用Promise的正确场景是这样的:

function runTimeP(){
	let timeP = new Promise((resolve,reject) => {
		setTimeout(function(){
			resolve('TimeP Success');
		},2000);
	});

	return timeP;
}

runTimeP()
.then((res) => {
        console.log('resolved1',res);
        return runTimeP();
    },(err) => {
        console.log('rejected1',err);
    }
)
.then((res) => {
        console.log('resolved2',res);
        return runTimeP();
    },(err) => {
        console.log('rejected2',err);
    }
)
.then((res) => {
        console.log('resolved3',res);
        return runTimeP();
    },(err) => {
        console.log('rejected3',err);
    }
)

打印结果:
在这里插入图片描述

  • 在上面的代码中,执行了一个异步操作setTimeout(),2秒后,调用resolve()
  • runTimeP()中传给resolve的数据,通过直接returnPromise对象,能在接下来的then()中拿到。
  • 实现了按顺序每隔两秒输出异步请求返回的结果,而且解决了回调地狱的问题。

Catch()的用法

  • catch()then()的第二个参数一样,用来指定reject的回调,效果和写在then()第二个参数里面一样。
  • catch()还有另外一个作用:在执行resolve的回调时,还会捕捉resolved抛出的异常。
function runTimeP(){
	let timeP = new Promise((resolve,reject) => {
		if (true) {
			setTimeout(function(){
				resolve('TimeP Success');
			},2000);
		} else {
			reject('Time Error');
		}
	});

	return timeP;
}

runTimeP()
.then((res) => {
	console.log(message);	//未定义message
	console.log(res);
})
.catch((res) => {
	console.log('rejected');
	console.log(res);
})

打印结果:
在这里插入图片描述

  • 上方代码中,在then()中打印了一个未声明的变量message,本来应该报错,但是Js没有报错,而且还运行了catch()中的内容。

All()的使用

  • Promise的all()提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。
  • all()的参数是对象数组。数组内所有的Promise对象状态为fulfiled时,该对象就为fulfiled。只要数组中有任意一个Promise对象状态为rejected,该对象就为rejected
let num = 0;
let timer = setInterval(function(){
	num++;
	console.log(num);
},1000)

function runTimeP1(){
	let timeP = new Promise((resolve,reject) => {
		setTimeout(function(){
			resolve('TimeP1 Success');
		},3000);
	})
	return timeP;
}
function runTimeP2(){
	let timeP = new Promise((resolve,reject) => {
		setTimeout(function(){
			resolve('TimeP2 Success');
		},5000);
	})
	return timeP;
}
function runTimeP3(){
	let timeP = new Promise((resolve,reject) => {
		setTimeout(function(){
			resolve('TimeP3 Success');
		},10000);
	})
	return timeP;
}

Promise.all([runTimeP1(),runTimeP2(),runTimeP3()])
.then((res) => {
	clearInterval(timer);
	console.log(res);
})

打印结果:
在这里插入图片描述

  • 三个Promise对象都为fulfiled,设置了setTimeout(),分别是3秒后,5秒后,10秒后。
  • 可以看到,使用了all()之后,所有异步操作执行完后才执行回调。

其中Promise对象存在rejected的情况:

let num = 0;
let timer = setInterval(function(){
	num++;
	console.log(num);
},1000)

function runTimeP1(){
	let timeP = new Promise((resolve,reject) => {
		setTimeout(function(){
			resolve('TimeP1 Success');
		},3000);
	})
	return timeP;
}
function runTimeP2(){
	let timeP = new Promise((resolve,reject) => {
		setTimeout(function(){
			reject('TimeP2 Error');
		},5000);
	})
	return timeP;
}
function runTimeP3(){
	let timeP = new Promise((resolve,reject) => {
		setTimeout(function(){
			resolve('TimeP3 Success');
		},10000);
	})
	return timeP;
}

Promise.all([runTimeP1(),runTimeP2(),runTimeP3()])
.then((res) => {
	clearInterval(timer);
	console.log(res);
})
.catch((res) => {
	clearInterval(timer);
	console.log(res);
})

打印结果:
在这里插入图片描述

  • 因为其中有一个Promise对象的状态为rejected,导致all()的状态也为rejected,结果并没有返回。
  • 有了all(),就可以并行执行多个异步操作,并且在一个then()中处理所有的返回数据。

Race()的用法

  • all()是在所有异步操作执行完后才执行回调。与all()相反,第一个异步操作执行完后,以它为准执行回调,这就是race()
  • race()的用法和all()一样,race()的参数也是数组对象,当数组中所有的Promise对象,有一个先执行了何种状态,该对象就为何种状态,并执行相应函数。
function runTimeP1(){
	let timeP = new Promise((resolve,reject) => {
		setTimeout(function(){
			resolve('TimeP1 Success');
		},3000);
	})
	return timeP;
}
function runTimeP2(){
	let timeP = new Promise((resolve,reject) => {
		setTimeout(function(){
			reject('TimeP2 Error');
		},5000);
	})
	return timeP;
}
function runTimeP3(){
	let timeP = new Promise((resolve,reject) => {
		setTimeout(function(){
			resolve('TimeP3 Success');
		},10000);
	})
	return timeP;
}

Promise.race([runTimeP1(),runTimeP2(),runTimeP3()])
.then((res) => {
	clearInterval(timer);
	console.log(res);
})
.catch((res) => {
	console.log(res);
})

打印结果:
在这里插入图片描述

  • race()执行了最早运行的runTimeP1()
  • race()可以用在请求获取上,设置setTimeout(),当获取超时,race()就会执行setTimeout()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值