什么是Promise
MDN定义:Promise对象用于异步操作,他表示一个尚未完成且预计在未来完成的异步操作。Promise
是异步编程的解决方案,相较传统的解决方案更加合理和强大。
回调函数
request('value1','',function(data1){
console.log('第一次请求成功', data1);request('value2', data1,function(data2){
console.log('第二次请求成功', data2);request('value3', data2,function(data3){
console.log('第三次请求成功', data3);//request... 继续请求},function(error3){
console.log('第三次请求失败', error3);});},function(error2){
console.log('第二次请求失败', error2);});},function(error1){
console.log('第一次请求失败', error1);});
上述例子出现了多层嵌套,这就是常说的回调地狱,而使用Promise
,可以利用then
进行链式回调,将异步操作以同步操作的流程表示出来。
sendRequest('value1','').then(function(data1){
console.log('第一次请求成功', data1);returnsendRequest('value2', data1);}).then(function(data2){
console.log('第二次请求成功', data2);returnsendRequest('value3', data2);}).then(function(data3){
console.log('第三次请求成功', data3);}).catch(function(error){//catch捕捉前面的错误
console.log('sorry, 请求失败了', error);});
Promise
有三种状态
pending
:初始值fulfilled
:操作成功rejected
:操作失败
Promise
的缺点:
Promise
一旦新建就会执行,无法中途取消- 若不设置回调函数,
Promise
内部抛出错误,不会反映到外部 - 处于
pending
状态时,无法得知目前是刚开始还是即将完成
Promise的基本用法
const promise=newPromise((resolve,reject)=>{if(/*异步操作成功*/){resolve(res);}else{/*异步操作失败*/reject(error);}})
我们构建一个Promise
,Promise
接受一个函数作为参数,该函数的两个参数分别是resolve
和reject
。它们是两个函数,由JavaScript引擎提供。resolve
: 异步操作成功时调用,并将操作结果以参数传递出去。reject
: 异步操作失败时调用,并将操作的报错以参数传递出去。
Promise实例生成后,使用then
方法指定resolved
状态和reject
状态的回调函数
promise.then((value)=>{//success},(error)=>{//failure});
then
方法可以接受两个回调函数作为参数,第一个函数是promise
对象的状态改变为resolved
是调用,第二个函数是promise
对象状态改变为rejected
时调用。第二个函数为可选。
Promise新建后会立即执行。then
方法中指定的回调函数,将在当前脚本所有同步任务执行完成后才会执行。
const promise=newPromise((resolve,reject)=>{
console.log('success);resolve();})
promise.then(()=>{
console.log('resolved');})
console.log('promsie')// success// promise// resolved
promise对象实现ajax操作:
constrequest=(param)=>{returnnewPromise((resolve,reject)=>{var xhr=newXMLHttpRequest();
xhr.open("get", param.url,true);
xhr.send(param.data);
xhr.responseType="json";
xhr.onreadystatechange=()=>{if(xhr.readyState===4){if(xhr.status===200){try{resolve(xhr.responseText+'success');}catch(err){reject(err)}}else{//failurereject(newError(xhr.statusText));}}}})}request(param).then((res)=>{
console.log(res);},(error)=>{
console.error(error);})
上述例子,request
是对XMLHttpRequest对象的封装,用于发出一个http请求,并返回一个Promise
对象。
Promise.prototype.then()
then
方法为Prommise实例添加状态改变时的回调函数,即resolved和rejected。then
方法返回一个新的Promise
对象,因此可以采用链式写法。
Promise.prototype.catch()
catch
方法用于指定发生错误时的回调函数。
request(param).then((res)=>{
console.log(res);}).catch((error)=>{
console.error(error);})//=========== 等同于 ===============request(param).then((res)=>{
console.log(res);}).then(undefined||null,(error)=>{
console.error(error);})
Promise抛出一个错误,就被catch的回调函数捕获
const promise=newPromise((resolve,reject)=>{thrownewError('error')});
promise.catch((error)=>{
console.log(error);})
上面代码的写法等同于
const promise=newPromise((resolve,reject)=>{try{thrownewError('error')}catch{reject(error);}});
从以上代码可以看出,reject
方法等同于抛出错误。
Promise对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。
const promise=newPromise((resolve,reject)=>{resolve(a+2)//此处报错 a未定义});
promise.then(()=>{
console.log('promise');})setTimeout(()=>{
console.log('promise test')},5000)// a is not defind// promise test
上面代码中,promise
对象的内部语法有错,浏览器会打印错误提示,但不会终止脚本执行,5秒后会输出promise test
,即promsie
内部的错误不会影响到外部的代码。
Promise.resolve()
Promise.resolve
能将现有的对象转为Promise对象,它可以看做是new Promise()
的快捷方式。
Promise.resolve(value)//=============等同于===================newPromise(resolve=>{resolve(value);})
Promise.reject()
该方法和Promise.resolve()
类似,也会返回一个Promise对象,该对象会进入rejected
状态,
Promise.all()
Promise.all()
用于将多个Promise实例,包装成一个新的Promise实例,该方法接受一个数组作为参数,数组的每一项都为一个Promise,若不是,会调用Promise.resolve()
方法,将参数转换为Promise实例。它的状态由参数中的Promise实例决定。
- 当数组中的Promise实例都为
fulfilled
,它的状态才会变为fulfilled
,并将Promise的返回结果按参数的顺序,存入数组。
var p1=newPromise(resolve=>{setTimeout(resolve,2000,"frist")})var p2=newPromise(resolve=>{resolve('second')})var p3=newPromise(resolve=>{setTimeout(resolve,500,"third")})
Promise.all([p1,p2,p3]).then(value=>{
console.log(value);})////["first","second","third"]
- 当数组中的Promise实例其中之一的状态变为
rejected
,它的状态也会变为rejected
,并把第一个被reject
的Promise的返回值传给回调函数。
var p1=newPromise(resolve=>{setTimeout(resolve,1000,"first")})var p2=newPromise((resolve,reject)=>{setTimeout(reject,500,"second")})var p3=newPromise((resolve,reject)=>{setTimeout(reject,500,"third")})
Promise.all([p1,p2,p3]).then(value=>{
console.log('resolve',value);},error=>{
console.log('reject',error);})//// reject second
Promise.race()
该方法同样用于将多个Promie实例包装成一个新的Promise实例,它与Promise.all()
方法一样,会将不是Promise实例的参数转换为Promise实例。与Promise.all()
不同于,当数组中有一个实例改变了状态,它的状态就会改变,并把率先改变的Promise实例的返回值,传递给回调函数。
var p1=newPromise((resolve,reject)=>{setTimeout(reject,2000,'one');})var p2=newPromise((resolve,reject)=>{setTimeout(resolve,1000,'two');})
Promise.race([p1,p2]).then(value=>{
console.log('resolve',value)},error=>{
console.log('reject',error)})//// resolve two