Promise是一个创建promise对象的构造函数,只能通过new关键字调用,不能直接调用,否则会报错,如下
promise存在三种状态:
pending
(进行中)fulfilled
(已成功)rejected
(已失败)一旦状态改变,就不会再变!
console.log(new Promise((resolve, reject)=>{ resolve(111) reject(222) })) // Promise {< fulfilled >: 111}
'运行
new Promise(executor)
executor:在构造函数中执行的 function。它接收两个函数作为参数:resolveFunc 和 rejectFunc。
executor 中抛出的任何错误都会导致 Promise 被拒绝,并且返回值将被忽略
[1] 在通过new关键字实例化promise对象时,必须传入一个函数。
函数在被执行时还会生成一对相应的 resolveFunc 和 rejectFunc 函数传入该函数中
new Promise((resolve, reject)=>{})
'运行
Promise一旦被创建就会立即执行并且无法中途取消,此时promise的状态为pending
executor 函数中的 return 语句仅影响控制流程,调整函数某个部分是否执行,但不会影响 Promise 的履行值
const res = new Promise((resolve, reject)=>{ return console.log(1111) // 不会执行 }) console.log(res) // Promise {
'} 运行
如上示例中,return会终止executor函数的执行,但是不会改变Promise的状态。
当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
[2] 状态改变
Promise对象的状态不受外界影响,只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态
new Promise((resolve, reject)=>{ // [1] 情况1 执行resolve函数时 Promise状态由pending转变为fulfilled // [2] 情况2 执行reject函数时,Promise状态由pending转变为rejected // [3] 状态3 抛出错误,Promise状态由pending转变为rejected(返回值被忽略) })
'运行
resolve、reject并不会终止 executor 函数后续执行
class Promise{ constructor(executor){ this.value = undefined this.reason = undefined this.status = 'pending' const resoveFun = value => { if (this.status == 'pending') { this.value = value this.status = 'fulfilled' } } const rejectFun = reason =>{ if (this.status == 'pending') { this.reason = reason this.status = 'rejected' } } try{ executor(resoveFun, rejectFun) }catch(err){ rejectFun(err) } } }
'运行
const res1 = new Promise((resove, reject)=>{})
console.log(res1) // {status: pending}
const res2 = new Promise((resove, reject)=>{ resove(111)})
console.log(res2) // {status: 'fulfilled', value: 111}
const res3 = new Promise((resove, reject)=>{ reject(222)})
console.log(res3) // {status: 'rejected', reason: 222}
const res4 = new Promise((resove, reject)=>{ resove(111) ; reject(222)})
console.log(res4) // {status: 'fulfilled', value: 111}
then方法是定义在原型对象Promise.prototype上的,作用是为 Promise 实例添加状态改变时的回调函数。
Promise.then(onFulfilled, onRejected)
then函数接收两个函数作为参数,分别是onFulfilled,onRejected
举例说明
const p1 = new Promise((resolve, reject)=>{ }) p1.then(res=>{ console.log(res) }, err=>{ console.log(err) })
'运行
此时控制台没有任何值打印出来
const p1 = new Promise((resolve, reject)=>{ resolve(111) }) p1.then(res=>{ console.log(res) }, err=>{ console.log(err) })
'运行
此时在控制台打印111
const p1 = new Promise((resolve, reject)=>{ reject(222) }) p1.then(res=>{ console.log(res) }, err=>{ console.log(err) })
'运行
此时打印222
在执行过程中如果Promise状态变为resolved,则会在当前脚本所有同步任务执行完毕时
会调用then方法指定的回调函数(并不是状态改变后立即调用)。
new Promise(function (resolve, reject) { console.log(111) resolve(222) console.log(333) }).then(data => { console.log(data) }) console.log(444)
'运行
执行结果为111、333、444、222
执行111结束就resolve了,但是并没有马上执行then方法而是等待所有的同步函数执行结束才去执行then函数。
同一个 promise 可以注册多个 then 方法,当 promise 完成或者失败后,对应的 then 方法按照注册顺序依次执行
。
const res = new Promise((resolve, reject)=>{ resolve(111) }) res.then(res=>{ console.log('111', res) }) res.then(res=>{ console.log('222', res) })
'运行
执行结果
then函数的返回值为一个新的
Promise
const p1 = new Promise(function (resolve, reject) { resolve(1) }) console.log(p1.then(data => {})) // Promise (
') 运行
通过上述代码可以看到then函数的返回值为一个新的Promise,这样我们可以使用then方法进行链式调用
const res = new Promise((resolve, reject)=>{ resolve(111) }) res.then(res=>{ console.log('111', res) // ‘111’ 111 return 222 }).then(res=>{ console.log('第二个res', res) // '第二个res' 222 })
'运行
class Promise{ constructor(executor){ this.value = undefined this.reason = undefined this.status = 'pending' this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; const resoveFun = value => { if (this.status == 'pending') { this.value = value this.status = 'fulfilled' this.onFulfilledCallbacks.forEach((cb) => cb(this.value)); } } const rejectFun = reason =>{ if (this.status == 'pending') { this.reason = reason this.status = 'rejected' this.onRejectedCallbacks.forEach((cb) => cb(this.value)); } } try{ executor(resoveFun, rejectFun) }catch(err){ rejectFun(err) } } then(onFulfilled, onRejected){ if (this.status == 'fulfilled') { onFulfilled(this.value) } if (this.status == 'rejected') { onRejected(this.reason) } if (this.status == 'pending') { this.onFulfilledCallbacks.push(onFulfilled); this.onRejectedCallbacks.push(onRejected); } } }
'运行
此处js代码模拟的Promise与Promise的区别是
微任务
,此处无法模拟,因此在resolve/reject后会同步执行then方法而非异步结果为1、3、2、2、4const res = new Promise((resolve,reject)=>{ console.log(111) resolve(222) console.log(333) }) res.then(data=>{ console.log('第一次:', data) }) res.then(data=>{ console.log('第二次', data) }) console.log(444)
'运行
const res = new Promise((resolve,reject)=>{ resolve(2) }) console.log(res.then(data=>{})) // undefined
'运行
catch方法是定义在原型对象Promise.prototype上的,用于指定发生错误时的回调函数。
1.在执行过程中如果Promise状态变为rejected,就会调用catch方法指定的回调函数.
new Promise(function (resolve, reject) { throw new Error('test') }) .then(data => { console.log('data', data) }) .catch(err => { console.log('err', err) // err Error: test })
'运行
2.then方法里面如果出现异常也会走catch函数,类似与try/catch
new Promise(function (resolve, reject) { resolve(111) }) .then(data => { throw new Error('test') }) .catch(err => { console.log('err', err) // err Error: test })
'运行
3.promise抛出的异常总会被后面的catch函数捕获,因此当使用链式调用时,最后跟随的catch方法可以捕捉前面任意then函数中的异常
finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作,当不论是成功还是失败都会执行的代码就可以走这个函数。
不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数
finally方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled还是rejected。这表明,finally方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果
需求:现在有两个请求,请求2需要请求1的请求结果作为参数,因此请求2需要等待请求1请求完毕之后再发送请求。
当使用链式调用时,最后跟随的catch方法可以捕捉前面任意then函数中的异常
const p1 = new Promise(function (resolve, reject) { // 模拟异步请求1-立即发送 setTimeout(function () { resolve(222) }, 0) }) function toP2 (value) { const p2 = new Promise(function (resolve, reject) { // 模拟异步请求2-封装在函数内部,等待请求1返回结果再发送 setTimeout(function () { resolve(value) }, 0) }) return p2 } p1.then(data1 => { console.log('请求1获取的数据', data1) // 222 return toP2(data1) }).then(data2 => { console.log('请求2获取的数据', data2) // 222 }).catch(err=>{ // 可以捕获前面所有then函数的异常 })
'运行
有时我们代码中存在多个异步请求,希望等待多个异步请求的结果才能进行下一步操作,就可以使用all方法。
Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);
上面代码中,Promise.all方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例
p的状态由p1、p2、p3决定,分成两种情况。
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
function f1 () { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('我是请求1的返回结果') }, 0) }) } function f2 () { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('我是请求2的返回结果') }, 500) }) } Promise.all([f1(), f2()]).then(data => { console.log('data', data) // ["我是请求1的返回结果", "我是请求2的返回结果"] })
'运行
function f1 () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('我是请求1的返回结果')
}, 0)
})
}
function f2 () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
throw new Error('失败')
}, 500)
})
}
Promise.all([f1(), f2()])
.then(data => {
console.log('data', data)
})
.catch(err => {
console.log('err', err) // err
})
有时我们代码中存在多个异步请求,希望等待多个异步请求中只要有1个请求的结果就能进行下一步操作,就可以使用race方法
Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3]);
上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
Promise.race()方法的参数与Promise.all()方法一样,如果不是 Promise 实例,就会先调用下面讲到的Promise.resolve()方法,将参数转为 Promise 实例,再进一步处理。
function f1 () { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('我是请求1的返回结果') }, 0) }) } function f2 () { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('我是请求2的返回结果') }, 500) }) } Promise.race([f1(), f2()]) .then(data => { console.log('data', data) // data 我是请求1的返回结果 }) .catch(err => { console.log('err', err) })
'运行
第一题:说出下列代码的输出结果
[1]
console.log(new Promise())
结果:error:Promise resolver undefined is not a function
解析:Promise构造函数必须接受一个函数为参数,否则会报错
[2]
console.log(new Promise(()=>{ return })) //
结果:Promise {< pending >}
解析:Promise的函数会立即执行,此时promise的状态为pending,状态不受外界影响->只有异步操作的结果,可以决定当前是哪一种状态
[3]
console.log(new Promise((resolve, reject)=>{ resolve(111) reject(222) }))
'运行
结果: Promise {< fulfilled >: 111}
解析: 当pending->fulfilled或rejected状态就凝固了,不会再变了
第二题:说出数字的输出顺序
console.log(1) // 执行 打印1 setTimeout(function () { console.log(2) }, 0) // 放入异步队列中 new Promise(resolve => { // Promise在新建后就会立即执行(执行传入的函数) console.log(3) resolve() console.log(4) }).then(() => { // 同步执行完毕后执行 console.log(5) }) // 同步代码-顺序执行 console.log(6)
'运行
新建后就会立即执行
(执行传入的函数),then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行