概念
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。
所`Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
特点
- 对象的状态不受外界影响。
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果。
状态
Promise
对象代表一个异步操作,有三种状态:
pending(进行中)、resolved(已成功)和rejected(已失败)。
只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
缺点
- 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
- 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
- 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
引子
请看以下代码
setTimeout(function(){
console.log('开始')
},Math.random()*1000);
setTimeout(function(){
console.log('执行')
},Math.random()*1000)
setTimeout(function(){
console.log('结束')
},Math.random()*1000);
那如何让以上代码先 开始 在 执行 最后在 结束呢(跟时间没有任何的关系)
如下:
setTimeout(function(){
console.log('开始')
setTimeout(function(){
console.log('执行')
setTimeout(function(){
console.log('结束')
},Math.random()*1000);
},Math.random()*1000)
},Math.random()*1000)
回调函数中有回调函数在有回调函数其实这种叫做回调地狱,而
promise
就是为了解决回调地狱的
promise
的三种状态
promise
可以理解为是一个机器
而机器是有三种状态的
- 待机(通过
new
关键词启动Promise
对象里面没有添加任何的对象就是待机状态):pending
(Promise
函数默认的状态) - 工作(成功)(通过
new
关键词启动的Promise
对象里面的回调函数,第一个参数启动是成功状态):resolved
(Promise
回调函数里面的第一个参数执行) - 故障(通过
new
关键词启动的Promise
对象里面的回调函数,第二个参数启动是失败(故障)状态):rejected
(Promise
回调函数里面的第二个参数执行)
以下是错误写法(没有在Promise
里面添加回调函数)
let p = new Promise();//通过new 关键词启动Promise对象 报错:表示语法错误
以下是Promise
的三种状态的写法
// 待机状态
let p = new Promise(function(){
})//现在才是生成promise对象
// 工作状态
let p = new Promise(function(reslove,reject){
reslove();//让reslove函数执行那么这个promise不在是待机状态而是工作状态
})
// 故障状态
let p = new Promise(function(reslove,reject){
reject();//让reject函数执行那么这个promise就是失败后的promise
})
通过new
关键词启动Promise
函数里面的回调函数
- 什么也没写默认是待机状态(
pending
) - 第一个参数是工作状态(
resolved
) - 第二个参数是故障状态(
rejected
)
promise
的使用方法
let p = new Promise(function(resolve,reject){
resolve('我成功了');
// [[PromiseStatus]]: "resolved"
// [[PromiseValue]]: "我成功了"
})
[[PromiseStatus]]
: 表示promise
的当前状态[[PromiseValue]]
: 表示promise
成功状态下传递的值
当Promise
对象状态码是'resolved'
(成功)就会触发then
函数的第一个回调函数
let p = new Promise(function(resolve,reject){
resolve('我成功了');
}).then((date)=>{//resolved状态的promise对象,就会触发then的第一个回调函数
console.log('函数触发')
console.log(date)
//成功状态下传递的信息会作为then函数第一个回调函数的参数
});
resolved
状态的promise
机器 会触发then
的第一个回调函数resolved
状态的的数据 会作为参数传递到第一个回调函数中
当Promise
对象状态码是'rejected'
(失败)就会触发then
函数的第二个回调函数
let p = new Promise(function(resolve,reject){
reject('我失败了');
}).then((date)=>{
console.log(date)
},(date)=>{
//当你Promise对象状态码是'rejected'(失败)的时候,就会触发then的第一个回调函数
console.log(date)
//失败状态下传递的信息会作为then函数第二个回调函数的参数
});
rejected
状态的promise
机器 会触发then
的第二个回调函数rejected
状态的的数据 会作为参数传递到第二个回调函数中
then
函数他返回的也是一个promise
对象,只要是promise
就就可以定义他的成功状态和失败状态
let p = new Promise(function(resolve,reject){
resolve('我成功了');
// reject('我失败了');
}).then((date)=>{
console.log(date)
// then函数的返回值默认是 return undefined(成功状态下的promise)
return '我是promise对象的返回值';//return 数据可以自己定义promise对象的返回值
// 那么怎么定义失败状态下的promise对象呢
return new Promise(function(resolve,reject){
reject('我失败了');//现在你then回调函中返回的是一个失败状态下的promise
//所以这个then函数返回结果就是失败状态下的promise
//(只有这种情况才能时then函数返回的结果是一个失败状态下的promise)
})
}
)
then
函数返回的结果也是一个promise
机器,这个机器的状态取决于触发的回调函数的返回值,只有回调函数返回一个失败状态的promise
,则then
函数的返回结果才是失败状态的promise
,否则 返回结果都是成功状态的promise
如果是Promise是失败的就会触发then的第二个回调函数,因为then的返回结果也是一台promise机器,那么当前then是成功状态下的还是失败状态下的promise的呢???
let p = new Promise(function(resolve,reject){
// resolve('我成功了');
reject('我失败了');
}).then((date)=>{
console.log(date)
},(date)=>{
console.log(date)
});
初始虽然是定义了失败状态下的promise
但是失败后的promise
是触发then的第二个回调,而then
他的返回结果是一台promise
机器而这他机器的状态取决于这个机器的状态取决于触发的回调函数的返回值当前的返回值是undefined
(可以人为设置)你只要不是返回结果是失败状态下的promise
那么都是成功状态下的promise
let p = new Promise(function(resolve,reject){
// resolve('我成功了');
reject('我失败了');
}).then((date)=>{//成功后触发then的第一个回调
console.log(date)
}).catch((date)=>{//失败后触发catch第一个回调
console.log(date)
})
当你定义一个失败的promise
机器的时候,失败后面的promise
机器会走到catch
函数里面,而成功后的promise
机器就会走到then
函数里面
then
和catch
同样的他们的返回结果都是一台promise
机器,而then
和catch
返回的promise
的状态决定你的回调函数的返回值
链式操作的用法
所以,从表面上看,Promise只是能够简化层层回调的写法,而实质上,Promise的精髓是“状态”,用维护状态、传递状态的方式来使得回调函数能够及时调用,它比传递callback函数要简单、灵活的多。所以使用Promise的正确场景是这样的:
new Promise(function(a,b){
setTimeout(()=>{
console.log('开始');
a('第一台机器');
},Math.random()*1000)
}).then(()=>{
return new Promise((a,b)=>{
setTimeout(()=>{
console.log('执行')
a('第二台机器');
},Math.random()*1000)
})
}).then(()=>{
setTimeout(()=>{
console.log('结束')
},Math.random()*1000)
})
Promise的方法
Promise.prototype.catch()
Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。
p1()
.then(function(data){
console.log(data)
})
.catch(function(err){
console.log(err)
})
//reject不能结束Promise
//>5,走reject
//如果不想promise机器报错 必须把错误信息catch
var z = new Promise(function(a,b){
b('我是失败了')
console.log('启动promise')
}).then((date)=>{
console.log(date)
}).catch((date)=>{
console.log(date)
return new Promise(function(a,b){
return b('我是自己定义的失败返回值')
})
})
z.catch(function(b){
console.log(b)
})
Promise.all()
Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
let p1 = new Promise(function (res,rej) {
setTimeout(()=>{
res('p1成功了');
},1000)
})
let p2 = new Promise(function (res,rej) {
setTimeout(()=>{
res('p2成功了');
},500)
})
let p3 = new Promise(function (res,rej) {
setTimeout(()=>{
res('p3成功了');
},300)
})
const p = Promise.all([p1, p2, p3]);
Promise.all([p1,p2,p3...])
- 如果所有的
promise
机器状态都是resolved
则all函数的返回结果就是resolved
- 如果有一个
promise
机器状态是rejected
则all函数的返回结果就是rejected
Promise.race()
Promise.race方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
let p1 = new Promise(function (res,rej) {
setTimeout(()=>{
res('p1成功了');
},1000)
})
let p2 = new Promise(function (res,rej) {
setTimeout(()=>{
res('p2成功了');
},500)
})
let p3 = new Promise(function (res,rej) {
setTimeout(()=>{
res('p3成功了');
},300)
})
const p = Promise.race([p1, p2, p3]);
上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
Promise.race([p1,p2,p3...])
,返回的是最早有状态的promise机器
Promise.resolve()
有时需要将现有对象转为 Promise 对象,Promise.resolve方法就起到这个作用。
const jsPromise = Promise.resolve('123');
上面代码将123转为一个 Promise 对象。
Promise.resolve
等价于下面的写法。
Promise.resolve('123')
// 等价于
new Promise(resolve => resolve('123'))
Promise.resolve(参数)
生成一个resolved状态的机器
Promise.reject()
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))
p.then(null, function (s) {
console.log(s)
});
// 出错了
上面代码生成一个 Promise 对象的实例p,状态为rejected,回调函数会立即执行。
注意,Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。这一点与Promise.resolve方法不一致。
Promise.reject(参数) 生成一个rejected状态的机器