js Promise详解

Promise

ECMAscript 6 原生提供了 Promise 对象。
Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息。

Promise 对象代表一个异步操作,有三种状态:
pending: 进行中
resolved: (又称 fulfilled ) 操作成功完成。
rejected: 操作失败。

只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。Promise 对象的状态改变,只有两种可能:从 pending 变为 resolved 和从 pending 变为 Rejected。

promise对象还有一个比较常用的then方法,用来执行回调函数,then方法接受两个参数,第一个是成功的resolved的回调,另一个是失败rejected的回调,第二个失败的回调参数可选。如果只接受了一个参数,那么就需要用catch来接收rejected的回调。

创建一个Promise实例:

var p=()=>{
	return new Promise((resolve,reject)=>{
		if(true){   //添加判断条件
			resolve('成功')
		}else{
			reject('失败')
		}
	})
}
//
p()
.then((data)=>{
	console.log(data)   //成功
},(error)=>{
	console.log(error)
})   //这里的then接受两个参数,第一个是resolve的回调,第二个则是reject的回调

p()
.then((data)=>{
	console.log(data)   //成功
})
.catch((error)=>{
	console.log(error) 
})//这个then只接收了一个参数,就是resolve的回调,用catch来接收reject

Promise链式调用
在then方法里面返回Promise对象,就可以实现链式调用。

1、先看看全部设置为 resolve 的例子

var p1=()=>{
  return new Promise((resolve,reject)=>{
      resolve('执行p1成功')
  })
}
var p2=(data)=>{
  return new Promise((resolve,reject)=>{
    console.log(data)
      resolve('执行p2成功')
  })
}
var p3=(data)=>{
  return new Promise((resolve,reject)=>{
    console.log(data)
      resolve('执行p3成功')
  })
}
p1().then(p2).then(p3).then((data)=>{
  console.log(data)
}).catch((error)=>{
  console.log(error)
})
//结果输出为
  //执行p1成功
  //执行p2成功
  //执行p3成功

2、部分设置为reject的例子

var p1=()=>{
  return new Promise((resolve,reject)=>{
      resolve('执行p1成功')
  })
}
var p2=(data)=>{
  return new Promise((resolve,reject)=>{
    console.log(data)
      reject('执行p2失败')     //设置为reject
  })
}
var p3=(data)=>{
  return new Promise((resolve,reject)=>{
    console.log(data)
      resolve('执行p3成功')
  })
}
p1().then(p2).then(p3).then((data)=>{
  console.log(data)
}).catch((error)=>{
  console.log(error)
})
//输出结果
//执行p1成功
//执行p2失败
在执行catch回调之后就不会在之后的then回调,
上述例子中p2返回reject就不会在执行then(p3)了

then的第二个参数onRejected和catch的用法介绍
虽然这两个方法都可以用来捕获错误,不过then的onRejected方法有个很明显的缺陷,就是当Promise的状态为resolve或者reject之后再抛出错误是不能够捕获到的。因为 Promise 的状态一旦改变,就永久保持该状态,不会再变了

new Promise((resolve, reject)=>{
  resolve('ok');
  throw new Error('test');
}).then((value)=>{ console.log(value) },
(error)=>{console.log(error)}) //ok  不能捕获异常

Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。

在链式调用中采用then的第二个参数来捕获异常
function taskA() { 
    console.log("Task A");
    throw new Error('test')
}
function taskB() {
    console.log("Task B");
}
function onRejected(error) {
    console.log("Catch Error: ", error);
}
Promise.resolve()
.then(taskA,()=>onRejected)
.then(taskB,()=>onRejected)  //Task A  没有捕获到异常,但是也不会输入Task B
//Promise 内部有未捕获的错误,会直接终止进程
Promise.resolve()
.then(taskA)
.then(taskB)
.catch(onRejected) //Task 同时输出异常

因此在Promise的链式调用中,最好不要在then方法里面定义 Reject 状态的回调函数(即then的第二个参数),总是使用catch方法。

Promise.all
Promise.all 方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个数组,而失败的时候则返回最先被reject的

var p1=()=>{
  return new Promise((resolve,reject)=>{
      resolve('执行p1成功')
  })
}
var p2=()=>{
  return new Promise((resolve,reject)=>{
      reject('执行p2失败')     //设置为reject
  })
}
var p3=()=>{
  return new Promise((resolve,reject)=>{
      resolve('执行p3成功')
  })
}
var p11=p1()
var p33=p3()
Promise.all([p11,p33]).then((results)=>{
  console.log(results)  //返回结果仍是["执行p1成功", "执行p3成功"]
}).catch((error)=>{
  console.log(error)
})

var p22=p2();
Promise.all([p11,p22,p33]).then((results)=>{
  console.log(results)  //返回结果为执行p2失败
}).catch((error)=>{
  console.log(error)
})

Promise.race
Promise.race 方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。不过它的返回值取决与第一个改变状态的实例的返回值。通俗的说就是哪个实例执行快就返回对应实例的返回值(不管是resolve还是reject状态)。

var p1=(time)=>{
  return new Promise((resolve,reject)=>{
      setTimeout(() => {
		resolve('执行p1成功')
      }, time);
  })
}
var p2=(time)=>{
  return new Promise((resolve,reject)=>{
      setTimeout(() => {
		reject('执行p2失败')
      }, time);
  })
}
//p1设置为3后执行,p2设置为2s后执行
Promise.race([p1(3000),p2(2000)]).then((results)=>{
  console.log(results)  
}).catch((error)=>{
  console.log(error)
})
//输出结果为  执行p2失败

来看一下链式调用的执行顺序:

setTimeout(() => {
  console.log('last')
}, 0);
Promise.resolve().then(()=>{console.log('resolve')})
new Promise((resolve,reject)=>{
  console.log('pro1')
  resolve()
}).then(()=>{
  console.log('then11')
  new Promise((resolve,reject)=>{
    console.log('pro2')
    resolve()
  }).then(()=>{
    console.log('then21')
  }).then(()=>{
    console.log('then22')
  })
}).then(()=>{
  console.log('then12')
})
// pro1  resolve  then11 pro2  then21  then12  then22  last

在同一个Promise对象中,如果存在多个then回调,以第一个回调完成为主,当第一个then执行之后,整个Promise对象的状态就已经确认了(resolve或者reject)。上面的代码中内部的Promise对象 ,执行完console.log(‘then21’)就进行如resolve状态,同时外部的Promise也随着内部的输出而进行了resolve状态,因此才会继续执行外部的第二个then回调。查看事件循环

你可能感兴趣的:(javascript)