Promise是什么?
- 抽象表单:Promise是JS异步编程的新解决方案(旧的是回调)
- 具体表达:
从语法上来说:Promise是一个构造函数
从功能上来说:promise对象是用来封装一个异步操作并可以获取其结果
promise状态改变
- 初始为pending
- pending变为resolved
- pending变为rejected
说明:只有这两种改变,且一个promise对象只能改变一次,无论成功还是失败,都会有一个结果数据;成功的结果一般称为value,失败的结果一般称为reason;
promise的基本流程
const p = new Promise((resolve,reject)=>{
if(Date.now() % 2 == 0){
resolve(1)
}else{
reject(0)
}
}).then(value=>{
console.log('成功的回调' + value) //1
},reason=>{
console.log('失败的回调' + reason) //0
})
为什么要用promise
- 指定回调函数更加灵活
旧的:必须在启动异步任务前指定回调函数
promise :启动异步任务=》返回promise对象=》给返回的promise对象绑定回调函数(甚至可以在异步任务结束后指定多个回调函数,异步任务前也可以指定)
- 支持链式调用,可以解决回调地狱的问题
什么是回调函数?回调函数嵌套调用,外部回调函数的异步执行结果是内部函数执行的条件;
回调地狱的缺点:不便于阅读,不便于异常处理
解决方案:promise链式调用
终极解决方案:async/await
如何使用promise
API
- Promise构造函数:Promise(excutor){}
(1) excutor函数:执行器excutor(resolve,reject)=>{}
(2) resolve函数:内部定义我们成功时调用的函数 value=>{}
(3) reject函数:内部定义我们失败时调用的函数 reason=>{}
说明:excutor会在promise内部立即同步执行,异步操作在执行器中执行 - promise.prototype.then 方法:(onResolved,onRejected)=>{}
(1) onResolved函数:成功的回调函数 (value)=>{}
(2) onRejected函数:失败的回调函数 (reason)=>{}
说明:指定用于得到成功value成功回调函数,和得到失败reason的失败回调函数,返回一个新的promise对象; - promise.prototype.catch 方法:(onRejected)=>{}
onRejected函数:失败的回调函数 (reason)=>{}
说明:then的语法糖,相当于:then(undefined,onRejected)=>{} - Promise.resolve方法:(value)=>{}
value:成功的数据或者promise对象
说明:返回一个成功/失败的promise对象 - Promise.reject方法:(reason)=>{}
reason:失败的原因
说明:返回一个失败的promise对象 - Promise.all方法:(promises)=>{}
promises:包含n个promise的数组
说明:返回一个新的promise对象,只有所有的promise都成功才返回成功,否则返回失败; - Promse.race方法:(promises)=>{}
promises:包含n个promise的数组
说明:返回一个新的promise对象,第一个完成promise的结果状态就是最终的状态;
Promise的几个关键问题
1.如何改变 promise的状态?
(1) resolve(value):如果当前是 pending就会变为 resolved
(2) reject(reason):如果当前是 pending就会变为 rejected
(3)抛出异常:如果当前是 pending就会变为 rejected
2.一个 promise指定多个成功/失败回调函数,都会调用吗?
当 promise改变为对应状态时都会调用
3. 改变 promise状态和指定回调函数谁先谁后
(1)都有可能,正常情况下是先指定回调再改变状态,但也可以先改状态再指定回调
(2)如何先改状态再指定回调?
①在执行器中直接调用 resolve()/ reject()
②延迟更长时间才调then()
(3)什么时候才能得到数据?
①如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据
②如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据
4. promise.then()返回的新 promise的结果状态由什么决定?
(1)简单表达:由then()指定的回调函数执行的结果决定
(2)详细表达
①如果抛出异常,新 promise变为 rejected, reason为抛出的异常
②如果返回的是非 promise的任意值,新 promise变为 resolved,value为返回的值
③如果返回的是另一个新 promIse,此 promIse的结果就会成为新 promise的结果
5. promise如何串连多个操作任务?
(1) promise的then()返回一个新的 promise,可以开成then()的链式调用
(2)通过then的链式调用串连多个同步/异步任务
6. promise异常传透
(1)当使用 promise的then链式调用时,可以在最后指定失败的回调
(2)前面任何操作出了异常,都会传到最后失败的回调中处理
(3) 不写失败回调函数相当于默认 reason=>{throw reason}
7.中断 promise链?
(1)当使用 promIse的then链式调用时,在中间中断,不再调用后面的回调函数
(2)办法:在回调函数中返回一个 pending状态的 promise对象
手写Promise
(function(){
const PENDING = 'pending' //初始状态
const RESOLVED = 'resolved' //成功状态
const REJECTED = 'rejected' //失败状态
//Promise构造函数
function MyPromise(excutor){
const self = this
//初始化状态
self.status = PENDING
self.data = undefined
self.callbacks = [] //每个元素的结构: {onResolved(value){}, onRejected(reason){} }
//resolve方法
function resolve(value){
if(self.status !== PENDING){
return
}
//改变状态,保存数据
self.status = RESOLVED
self.data = value
//如果有待执行回调函数,立即异步执行异步回调函数
if(self.callbacks.length > 0){
setTimeout(()=>{
self.callbacks.forEach(item=>{
item.onResolved(value)
})
})
}
}
//reject方法
function reject(reason){
if(self.status !== PENDING){
return
}
//改变状态,保存数据
self.status = REJECTED
self.data = reason
//如果有待执行回调函数,立即异步执行异步回调函数
if(self.callbacks.length > 0){
setTimeout(()=>{
self.callbacks.forEach(item=>{
item.onRejected(reason)
})
})
}
}
//立即执行excutor函数
try{
excutor(resolve,reject)
}catch(error){
reject(error)
}
}
//Promise对象的then方法
MyPromise.prototype.then = function(onResolved,onRejected){
onResolved = typeof onResolved === 'function' ?onResolved : value => value, //不写默认undefined
//指定默认是失败回调
onRejected = typeof onRejected === 'function' ?
onRejected : reason => {
throw reason
}
const self = this
//返回一个新的promise对象
return new MyPromise((resolve,reject)=>{
function handle(callback){
try{
//回调函数返回的结果
const result = callback(self.data)
if(result instanceof MyPromise){
//返回的数据是Promise
result.then(resolve,reject)//返回新的promise对象
}else{
resolve(result)
}
}catch(error){
reject(error)
}
}
if(self.status === PENDING){
self.callbacks.push({
onResolved(value){
handle(value)
},
onRejected(reason){
handle(reason)
}
})
}else if(self.status === RESOLVED){
setTimeout(()=>{
handle(onResolved)
})
}else{
setTimeout(()=>{
handle(onRejected)
})
}
})
}
//Promise对象的catch方法
MyPromise.prototype.catch = function(onRejected){
return this.then(undefined, onRejected)
}
//Promise的resolve方法
MyPromise.resolve = function(value){
return new MyPromise((resolve,reject)=>{
if(result instanceof MyPromise){
//返回的数据是Promise
result.then(resolve,reject)//返回新的promise对象
}else{
resolve(result)
}
})
}
//Promise的reject方法
MyPromise.reject = function(reason){
return new MyPromise((resolve,reject)=>{
reject(reason)
})
}
//Promise的all方法
MyPromise.all = function(promises){
const values = new Array(promises.length) //保存成功的数据数据
let resolvedCount = 0 //成功的数量
return new MyPromise((resolve,reject)=>{
//遍历执行promises
promises.forEach((item,index)=>{
MyPromise.resolve(item).then(
value=>{
reslovedCount++
values[index] = value
if(reslovedCount === promises.length){
resolve(values)
}
},
reason=>{
reject(reason)
}
)
})
})
}
//Promise的race方法
MyPromise.race = function(promises){
return new MyPromise((resolve,reject)=>{
promises.forEach((item,index)=>{
MyPromise.resolve(item).then(
value=>{
resolve(value)
},
reason=>{
reject(reason)
}
)
})
})
}
window.MyPromise = MyPromise
})()
//使用
var p = new MyPromise((resolve,reject)=>{
resolve(1)
})
async与await
- async函数
- 函数的返回值为 promise对象
- promise对象的结果由 async函数执行的返回值决定
- await表达式
- await右侧的表达式一般为 promise对象,但也可以是其它的值
- 如果表达式是 promise对象,awat返回的是 promise成功的值
3.注意await必须写在 async函数中,但 async函数中可以没有 await如果 await的 promise失败了,就会抛出异常,需要通try. catch来捕获处理