1.什么是Promise?
Promise是异步编程的一种解决方案:从语法上讲,promise是一个对象,从它可以获取异步操作的消息;从语义上讲,它是承诺,承诺它过一段时间会给你一个结果。
Promise有三种状态:pending(等待态),fulfilled(成功态),rejected(失败态)
Promise有两个特点:
(1).对象的状态不受外界影响。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态;
(2).一旦状态改变,就不会再变。Promise对象的状态改变只有两种可能:从pending变为fulfilled(成功)和从pending变为rejected(失败)。
2.Promise解决了什么?
先来了解一下回调函数:
function fn1(a, callback) {
if (a > 1 && typeof callback === 'function') {
callback()
}
}
fn1(5, function () {
console.log('this is a callback')
})
这段代码当fn1执行完成以后,再执行回调函数输出‘this is a callback’,这里的回调嵌套非常简单,但某些情况下,回调嵌套很多时,代码就会非常复杂,这种情况俗称——回调地狱,如:
fn1(5, function () {
console.log('this is a callback1')
fn1(6, function () {
console.log('this is a callback2')
fn1(7, function () {
console.log('this is a callback3')
fn1(0, function () {
console.log('this is a callback4')
})
})
})
})
// 执行结果:
// this is a callback1
// this is a callback2
// this is a callback3
因此Promise应运而生了,它解决了两个问题:
(1).回调地狱
(2).Promise可以支持多个并发的请求,获取并发请求中的数据
3.Promise用法
Promise是一个构造函数,自己本身有all、reject、resolve这几个常用的方法,原型上有then、catch等常用的方法
创建一个Promise
既然是构造函数,那就来new一个
let p = new Promise((resolve, reject) => {
// 异步操作执行成功
if (true) {
resolve('执行成功')
}
// 异步操作执行失败
else {
reject('执行失败')
}
})
Promise的构造函数接受一个参数,这个参数是一个函数,并且这个函数需要传入两个参数:
resolve:异步操作执行成功后的回调函数
reject:异步操作执行失败后的回调函数
then的用法
then方法可以接受两个回调函数作为参数,第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用,其中第二个参数是可选的
p.then((data) => {
console.log(data) // 执行成功
}, (err) => {
console.log(err) // 执行失败
})
catch的用法
除了在then方法中传入第二个参数来获取失败的回调之外,还有一个catch方法也可以指定reject的回调:
p.then((data) => {
console.log(data) // 执行成功
}).catch((err) => {
console.log(err) // 执行失败
})
这个效果和在then中写第二个参数是一样的,不过它还有另外一个作用:在执行resolve的回调时,如果抛出异常,那么并不不会报错卡死js,而是会进入到这个catch方法中,如:
p.then((data) => {
console.log(data) // 执行成功
console.log(a)
}).catch((err) => {
console.log('进入到了这里面')
console.log(err) // 执行失败
})
运行结果:由于a并没有声明,所以进入到了catch中
then的链式用法
先了解一下then方法的有哪些特点:
(1).then方法的下一次的输入需要上一次的输出
示例:因为这里的then没有通过resolve传入结果,所以then没有执行
let p1 = new Promise((resolve, rejeced) => {
console.log('执行到这里')
})
p1.then((val) => {
console.log(val, 'val')
})
// 执行结果:
// 执行到这里
如果通过resolve返回结果:
let p1 = new Promise((resolve, rejeced) => {
resolve('成功')
})
p1.then((val) => {
console.log(val)
})
// 执行结果:
// 成功
(2).如果一个promise执行完后,返回的还是一个promise,会把这个promise的执行结果,传递给下一次then中
示例:
let p1 = new Promise((resolve, rejeced) => {
resolve(1)
})
p1.then((val) => {
console.log(val, '第一个val')
let p2 = new Promise((resolve, rejeced) => {
resolve(2)
})
return p2
}).then((val) => {
console.log(val, '第二个val')
})
// 执行结果:
// 1 '第一个val'
// 2 '第二个val'
(3).如果then中返回的不是promise对象而是一个普通值,则会将这个结果作为下次then的成功的结果
示例:
let p1 = new Promise((resolve, rejeced) => {
resolve(1)
})
p1.then((val) => {
console.log(val, '第一个val')
return '返回值'
}).then((val) => {
console.log(val, '第二个val')
})
// 执行结果:
// 1 '第一个val'
// 返回值 第二个val
(4).如果当前then中失败了,会走下一个then的失败
示例:
let p1 = new Promise((resolve, rejeced) => {
resolve(1)
})
p1.then((val) => {
console.log(a)
}).then((val) => {
console.log('成功')
}).catch((err) => {
console.log('失败')
})
// 执行结果:
// 失败
(5).如果返回的是undefined,不管当前是成功还是失败,都会走下一次成功
(6).catch是错误没有处理的情况下才会走
(7).then中如果不写方法,值会穿透,传入下一个then中
let p1 = new Promise((resolve, rejeced) => {
resolve(1)
})
p1.then('haha').then((val) => {
console.log(val, '成功')
}).catch((err) => {
console.log('失败')
})
// 执行结果:
// 1 '成功'
all的用法
Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调
谁最后执行完,就以谁为准执行回调。all接收一个数组参数,里面的值最终都会返回Promise对象
let Promise1 = new Promise(function(resolve, reject) {
resolve(1)
})
let Promise2 = new Promise(function(resolve, reject) {
resolve(2)
})
let Promise3 = new Promise(function(resolve, reject) {
resolve(3)
})
let p = Promise.all([Promise1, Promise2, Promise3])
p.then(() => {
console.log('三个都成功才成功')
}).catch(() => {
console.log('只要有一个失败,就失败')
})
// 三个都成功才成功
let Promise1 = new Promise(function(resolve, reject) {
resolve(1)
})
let Promise2 = new Promise(function(resolve, reject) {
resolve(2)
})
let Promise3 = new Promise(function(resolve, reject) {
reject('失败了')
})
let p = Promise.all([Promise1, Promise2, Promise3])
p.then(() => {
console.log('三个都成功才成功')
}).catch((err) => {
console.log('只要有一个失败,就失败')
console.log(err)
})
// 只要有一个失败,就失败
// 失败了
race的用法
谁最先执行完,就以谁为准执行回调
比如现在有这样一个例子,promise1会异步加载一张图片,promise2会在五秒后提示请求超时,把这两个Promise对象放入race中,它们两就会开始赛跑,如果5秒内图片加载成功了,promise1执行了resolve回调,那么就进入了then方法,执行成功的流程;如果5秒后图片还没加载成功,那么promise2执行了reject回调,进入catch,抛出错误提示信息。
let promise1 = new Promise((resolve, reject) => {
// 如果图片加载成功
if (true) {
resolve('img加载成功')
}
})
let promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('图片请求超时')
}, 5000)
})
let p = Promise.race([promise1, promise2])
p.then((data) =>{
console.log(data)
}).catch((err) => {
console.log(err)
})
4.实现Promise
步骤一:创建Promise的构造函数
我们先来创建一个Promise类,用class关键字来声明
● 由于 new Promise((resolve, reject) => {...}) ,需要传入一个参数(函数),这个函数叫executor
● executor中有两个参数,一个是resolve(成功),一个是reject(失败)
● 由于resolve和reject是可以执行的,所以都是函数
代码如下:
class Promise{
// 构造器
constructor(executor){
// 成功
let resolve = () => { }
// 失败
let reject = () => { }
// 立即执行
executor(resolve, reject)
}
}
步骤二:解决基本状态
● Promise存在三个状态(state):pending(等待态)、fulfilled(成功态)、rejected(失败态)
● pending(等待态)为初始态,并且可以转化为fulfilled(成功态)和rejected(失败态)
● 成功时,不可转为其它状态,且必须有一个不可改变的值(value)
● 失败时,不可转为其它状态,且必须有一个不可改变的原因(reason)
● new Promise((resolve, reject)=>{resolve(value)}) resolve为成功,接收参数value,状态改变为fulfilled,不可再次改变
● new Promise((resolve, reject)=>{reject(reason)}) reject为失败,接收参数reason,状态改变为rejected,不可再次改变
● 若是executor函数报错 直接执行reject()
代码如下:
class Promise{
// 构造器
constructor(executor){
// 初始化state为等待态
this.state = 'pending'
// 成功的值
this.value = undefined
// 失败的原因
this.reason = undefined
// 成功
let resolve = (value) => {
// 如果state不是pending,说明发生改变,resolve调用就会失败
if (this.state === 'pending') {
// resolve调用后,state会变成成功态
this.state = 'fulfilled'
// 储存成功的值
this.value = value
}
}
// 失败
let reject = (reason) => {
// 如果state不是pending,说明发生改变,reject调用就会失败
if (this.state === 'pending') {
// reject调用后,state转化为失败态
this.state = 'rejected'
// 储存失败的原因
this.reason = reason
}
}
// 如果执行executor报错,直接执行reject
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
}
步骤三:实现Promise的then方法
代码:
class Promise{
// 构造器
constructor(executor){
// 初始化state为等待态
this.state = 'pending'
// 成功的值
this.value = undefined
// 失败的原因
this.reason = undefined
// 存放成功的回调
this.onResolvedCallbacks = []
// 存放失败的回调
this.onRejectedCallbacks = []
// 成功
let resolve = (value) => {
// 如果state不是pending,说明发生改变,resolve调用就会失败
if (this.state === 'pending') {
// resolve调用后,state会变成成功态
this.state = 'fulfilled'
// 储存成功的值
this.value = value
// 执行成功的回调
this.onResolvedCallbacks.forEach(fn => fn())
}
}
// 失败
let reject = (reason) => {
// 如果state不是pending,说明发生改变,reject调用就会失败
if (this.state === 'pending') {
// reject调用后,state转化为失败态
this.state = 'rejected'
// 储存失败的原因
this.reason = reason
// 执行失败的回调
this.onRejectedCallbacks.forEach(fn => fn())
}
}
// 如果执行executor报错,直接执行reject
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
}
// 实现Promise的then方法(参数有onFulfilled,onRejected)
Promise.prototype.then = function(onFulfilled, onRejected) {
// 由于then方法是异步的(微任务)
setTimeout(() => {
let self = this
// 成功时会调用所有的成功的方法
if (self.state === 'fulfilled') {
onFulfilled(this.value)
}
// 失败时会调用所有的失败的方法(前提是传入了onRejected函数,不判断会报错)
if (onRejected && self.state === 'rejected') {
onRejected(this.reason)
}
// 因为异步延迟了Promise状态的改变,then先执行了,所以使用发布订阅等状态改变之后再统一执行
if (self.state === 'pending') {
self.onResolvedCallbacks.push(() => {
onFulfilled(this.value)
})
// 前提是传入了onRejected函数
if (onRejected) {
self.onRejectedCallbacks.push(() => {
onRejected(this.reason)
})
}
}
}, 0)
}
现在来试试看这个Promise能不能用:
let p1 = new Promise((resolve, rejeced) => {
resolve('resolve')
})
p1.then((val) => {
console.log(val, '成功')
}, (reason) => {
console.log(reason, '失败')
})
// 执行结果:
// resolve 成功
let p1 = new Promise((resolve, rejeced) => {
rejeced('rejeced')
})
p1.then((val) => {
console.log(val, '成功')
}, (reason) => {
console.log(reason, '失败')
})
// 执行结果:
// rejeced 失败
步骤四:实现then的链式调用
链式调用成功会返回值,有很多情况。因此将链式调用返回的值单独写一个方法,方法中传入四个参数,分别是promise2,x,resolve,reject;
promise2指的是上一次返回的promise
x表示运行promise返回的结果
resolve和reject是promise2的方法
class Promise{
// 构造器
constructor(executor){
// 初始化state为等待态
this.state = 'pending'
// 成功的值
this.value = undefined
// 失败的原因
this.reason = undefined
// 存放成功的回调
this.onResolvedCallbacks = []
// 存放失败的回调
this.onRejectedCallbacks = []
// 成功
let resolve = (value) => {
// 如果state不是pending,说明发生改变,resolve调用就会失败
if (this.state === 'pending') {
// resolve调用后,state会变成成功态
this.state = 'fulfilled'
// 储存成功的值
this.value = value
// 执行成功的回调
this.onResolvedCallbacks.forEach(fn => fn())
}
}
// 失败
let reject = (reason) => {
// 如果state不是pending,说明发生改变,reject调用就会失败
if (this.state === 'pending') {
// reject调用后,state转化为失败态
this.state = 'rejected'
// 储存失败的原因
this.reason = reason
// 执行失败的回调
this.onRejectedCallbacks.forEach(fn => fn())
}
}
// 如果执行executor报错,直接执行reject
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
}
//用来解析回调函数的返回值x,x可能是普通值也可能是个promise对象
function resolvePromise(promise2, x, resolve, reject) {
// x和promise2不能是同一个对象,不能自己等待自己完成
if (promise2 === x) {
return reject(new TypeError('循环引用'))
}
// x是对象或者函数
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
//防止成功后调用失败
let called
try {
// 获取x的then方法
let then = x.then
if (typeof then === 'function') { // 如果then是函数就认为他是promise
// call第一个参数是this,后面的是成功的回调和失败的回调
then.call((x, y) => {
if (called) return
called = true
resolvePromise(promise2, y, resolve, reject)
}, r => { // 只要失败了就失败了
if(called) return
called = true
reject(r)
})
} else {
resolve(x)
}
} catch (e) {
if(called) return
called = true
reject(e)
}
} else { // 当x为普通值的时候,作为下个then成功的参数
resolve(x)
}
}
// 实现Promise的then方法(参数有onFulfilled,onRejected)
Promise.prototype.then = function(onFulfilled, onRejected) {
// 成功和失败的回调,是可选参数
// 校验参数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }
let self = this
let promise2 = null
// 每次调用的then时都返回一个新的promise
promise2 = new Promise((resolve, reject) => {
// 成功的时候
if (self.state === 'fulfilled') {
setTimeout(() => {
try {
// 当执行成功回调的时候 可能会出现异常,那就用这个异常作为promise2的错误的结果
let x = onFulfilled(self.value)
//执行完当前成功回调后返回结果可能是promise
resolvePromise(promise2,x,resolve,reject)
} catch (e) {
reject(e)
}
}, 0)
}
// 失败的时候
if (self.state === 'rejected') {
setTimeout(()=>{
try {
let x = onRejected(self.reason)
resolvePromise(promise2,x,resolve,reject)
} catch (e) {
reject(e)
}
},0)
}
// 既没有成功也没有失败(状态没改变的时候)
if (self.state === 'pending') {
self.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(self.value)
resolvePromise(promise2,x,resolve,reject)
} catch (e) {
reject(e)
}
}, 0)
})
self.onRejectedCallbacks.push(() => {
setTimeout(()=>{
try {
let x = onRejected(self.reason)
resolvePromise(promise2,x,resolve,reject)
} catch (e) {
reject(e)
}
},0)
})
}
})
return promise2
}
这时候来验证一下then的链式调用:
let p1 = new Promise((resolve, rejeced) => {
resolve('resolve')
})
p1.then((val) => {
console.log(val, '成功')
return val
}, (reason) => {
console.log(reason, '失败')
}).then((val) => {
console.log(val, '成功2')
})
// 执行结果:
// resolve 成功
// resolve 成功2
步骤5:实现catch方法
要是先catch方法很简单,只需要传入then的第二个参数(函数)就行了
// 实现Promise的catch方法(只有一个参数)
Promise.prototype.catch = function (onRejected) {
return this.then(null, onRejected)
}
验证结果:
let p1 = new Promise((resolve, rejeced) => {
rejeced('rejeced')
})
p1.then((val) => {
console.log(val, 'val')
}).catch((reason) => {
console.log(reason, '失败')
})
// 执行结果:
// rejeced 失败
其它方法的实现:
//resolve方法
Promise.resolve = function(val) {
return new Promise((resolve, reject) => {
resolve(val)
})
}
//reject方法
Promise.reject = function(val) {
return new Promise((resolve, reject) => {
reject(val)
})
}
//race方法
Promise.race = function(promises) {
return new Promise((resolve, reject) => {
for(let i=0; i<promises.length; i++){
promises[i].then(resolve, reject)
}
})
}
//all方法(获取所有的promise,都执行then,把结果放到数组,一起返回)
Promise.all = function(promises) {
let arr = []
let i = 0
function processData(index, data) {
arr[index] = data
i++
if(i == promises.length){
resolve(arr)
}
}
return new Promise((resolve,reject)=>{
for(let i = 0; i < promises.length; i++){
promises[i].then( data =>{
processData(i, data)
}, reject)
}
})
}
如果这篇文章对你有帮助,请点个赞再走吧