Promise简介
es6引入的异步编程解决方案,从语法上来说就是一个构造函数可以封装异步的任务,并且对结果进行处理。最大的优点是能解决回调地狱问题,同时在对错误处理也更加灵活方便
常见的异步操作有:fs文件操作、数据库操作、AJAX、定时器
为什么要用Promise
-
指定回调函数的方式更加灵活
-
在之前的异步任务中回调函数必须在异步任务启动前指定
-
promise可以先启动异步任务等返回promise对象后再给promise对象绑定回调函数,甚至可以在异步任务结束后指定多个
-
-
支持链式调用,解决回调地狱问题
-
什么是回调地狱?
回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件,回调函数不便于阅读与异常处理
-
Promise的基本流程
Promise实现
基本语法:new Promise(executor),executor是执行器为一函数如,(res,rej)=>{},执行器在Promise内部了同步调用,而异步操作在执行器中执行
var p=new Promise((res,rej)=>{
var j=2
if(j==2){
res();//res为成功时调用的函数,调用完后会将promise对象的状态设置为成功
}else{
rej()//rej为失败时调用的函数,调用完后会将promise对象的状态设置为失败
}
})
Promise.prototype.then方法
基本语法:p.then(onResolved,onRejected)。then中的两个参数都为函数,onResolved是成功时调用的函数,onRejected是失败时调用的函数
p.then(()=>{
console.log("我是成功时res调用的函数")
},()=>{
console.log("我是失败时rej调用的函数")
})
Promise.prototype.catch方法
基本语法:p.catch(OnRejected)。onRejected是失败时调用的函数
它内部为then(null,failureCallback)的简化
p.catch(()=>{
console.log("我是失败时rej调用的函数")
})
Promise.resolve()
-
返回一个成功或失败的Promise对象
-
如果传入的参数为非promise类型的对象,则返回的结果为成功promise对象
-
如果传入的参数为Promise对象,则参数的结果决定了resolve的结果
Promise.resolve(new Promise((res,rej)=>{ //若此Promise对象返回的是res成功对象则外侧Promise返回的也是成功, //若此对象返回rej失败对象则外侧Promise返回的也是失败 }))
Promise.reject方法
语法:Promise.reject(()=>{})
-
返回一个失败的Promise对象
-
无论传入的参数为什么类型的对象都会得到失败的结果
Promise.all方法
语法:Promise.all((promises)=>{})
-
promises为包含n个promise的数组
-
返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败就直接失败
var p1=new Promise((resolve,reject)=>{ resolve('OK') }) var p2=Promise.resolve('yes') var p3=Promise.resolve('yes two') const result=Promise.all([p1,p2,p3])//p1、p2、p3都是成功值所以result为成功
Promise.race方法
语法:Promise.race(promises=>{})
-
promise为包含n个promise的数组
-
返回一个新的promise,第一个完成的promise的结果状态为最终的结果状态
var p1=new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve('OK') },1000) }) var p2=Promise.resolve('yes') var p3=Promise.resolve('yes two') const result=Promise.race([p1,p2,p3]) //因为p1加入了定时器在一秒后才返回结果状态,所以race中第一个返回结果状态的是p2因此以上最终结果为p2的值
promise关键问题
-
如何改变promise状态
-
resolve(value):由pending改为resolved
-
reject(value):由pending改为rejected
-
抛出异常(throw "字符串"):如果当前是pending会变为rejected
-
-
一个promise指定多个成功/失败回调函数,都会调用吗?
当promise改变为对应状态时都会调用
-
改变promise状态和指定回调函数谁先谁后?
指定回调函数用then和catch,改变状态用resolve()和reject()
-
都有可能,正常情况下是先指定回调再改变状态,也可以先改状态再指定回调
当执行器中的是同步任务时先改变状态再指定回调,当执行器中是异步任务时先指定回调再改变状态
-
如何先改状态再指定回调?
在执行器中直接调用resolve()或reject()
延迟更长时间才调用then()
-
什么时候才能得到数据?
意思就是回调函数then什么时候执行
如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据
如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据。
-
-
promise.then()返回的新promise的结果状态由什么决定
简单表达:由then()指定和回调函数执行的结果决定
详细表达:
-
如果抛出异常,新promise变成rejected,reason为抛出的异常
result=p.then(value=>{ throw '错误' },reason=>{ }) //result变为rejected类型promise
-
如果返回的是非promise的任意值,新promise变成resolved,value为返回的值
result=p.then(value=>{ return 'hello' },reason=>{ }) //result变为resolved类型promise
-
如果返回的是另一个新promise,此promise的结果就会成为新promise的结果
result=p.then(value=>{ return new Promise((resolve,reject)=>{ resolve('success') }) },reason=>{ }) //因为返回的是一个新Promise对象且为成功,因此result也为成功的Promise对象
-
-
promise如何串连多个操作任务?
-
promise的then()返回一个新的promise,可以形成then()的链式调用
-
通过then的链式调用串连多个同步或异步任务
-
-
promise异常传透
当使用promise的then链式调用时,可以在最后指定失败在回调,当前面任何操作出了异常都会传到最后失败的回调中处理
-
中断promise链
当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数
方法:在回调函数中返回一个pendding状态的promise对象
util.promisify方法
将异步回调方法改成返回Promise实例的方法
对fs.readFile方法进行更改
//引入util模块
const util=require('util')
//引入fs模块
const fs=require('fs')
//引入path模块
const path = require('path')
//拼接地址
var filepath = path.join(__dirname, 'page.html')
//对异步方法进行更改,返回一个新的函数
let mineReadFile=util.promisify(fs.readFile)
mineReadFile(filepath).then(val=>{
console.log('读取文件成功')
},va => {
console.log('读取失败')
}).
原fs.readFile()方法
fs.readFile(filepath, (err, data) => {
if (err) console.log('读取失败')
else console.log('读取成功')
})
Promise实例对象的属性
-
PromiseState
为Promise的状态,有pending、resolved与rejected三种值。一个promise对象只有pending、resolved与rejected三种状态,但只有两种改变:由pending变为resolved状态;由pending变为rejected状态。且状态只能改变一次,无论成功还是失败都会有一结果数据
-
PromiseResult
对象成功或失败的结果