Promise从入门到放弃
Promise的理解与使用
Promise的理解
Promise是什么
抽象的表达就是:Promise 是异步编程的一种解决方案。
而具体点的表达就是:
在语法上:Promise 是一个构造函数;
在功能上:Promise 对象是用来封装一个异步操作并可以从中获取结果;
Promise的状态
Promise 只有三种状态,分别为初始状态(pending)、成功状态(fulfilled / resolved)、失败状态(rejected)。
pending(初始状态): 初始状态,既不是成功,也不是失败状态;
fulfilled / resolved(已成功): 意味着操作成功完成;
rejected(已失败): 意味着操作失败;
而在这三种状态之间,Promise 对象的状态改变只有两种情况,分别是:
从初始状态(pending)变为成功状态(fulfilled / resolved);
从初始状态(pending)变为失败状态(rejected);
只要上面这两种情况发生了,状态就凝固了,不会再变了,会一直保持这个结果。
一个 Promise 对象只能改变一次状态,无论最后是变成成功还是失败,都会有一个数据结果。
为什么要用Promise
使用 Promise 的原因有如下两点:
指定回调函数的方式更加灵活
支持链式调用,可以解决回调地狱的问题
那么回调地狱又是什么呢?
回调地狱即回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调的执行条件。
而回调地狱十分不便于开发者阅读,也不利于进行异常处理。因此,使用 Promise 的链式调用可以解决此类问题。
Promise的基本使用
Promise 的基本书写语法大致如下:
function fn() {
return new Promise((resolve, reject) => {
成功时调用 resolve(value)
失败时调用 reject(error)
})
}
fn().then(成功函数1, 失败函数1).then(成功函数2, 失败函数2)
let p = new Promise((resolve, reject) => {
setTimeout(() => {
let time = Date.now()
console.log(time)
if (time % 2 === 1) {
resolve(time)
} else {
reject(time)
}
}, 1000)
})
p.then((value) => {
console.log('成功的回调' + value)
}, (error) => {
console.log('失败的回调' + error)
})
Promise的API
Promise.prototype.then
Promise 实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。该方法返回一个新的 promise 对象。
它的作用是为 Promise 实例添加状态改变时的回调函数。then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。
let p1 = new Promise((resolve, reject) => {
...
})
p1.then(value => {...}, error => {...})
Promise.prototype.catch
Promise.prototype.catch() 方法是 .then(null, rejected) 或 .then(undefined, rejected) 的别名,用于指定发生错误时的回调函数。
let p1 = new Promise((resolve, reject) => {
reject('error')
})
p1.then(value => {
console.log(value)
}).catch(error => {
console.log(error)
})
Promise.resolve
Promise.resolve() 返回一个成功 Promise 对象。
// value: 成功的数据或 Promise 对象 Promise.resolve(value)
let p1 = Promise.resolve('p1')
// 等价于
let p1 = new Promise(resolve => {
resolve('p1')
})
Promise.reject
Promise.reject() 返回一个失败的 Promise 对象。
// error: 失败的原因 Promise.reject(error)
let p2 = Promise.reject('error')
// 等价于
let p2 = new Promise((resolve, reject) => {
reject('error')
})
Promise.all
Promise.all() 方法用于将多个 Promise 实例包装成一个新的 Promise 实例。传入的参数为数组形式。
该 Promise 对象在数组参数对象里所有的 Promise 对象都成功的时候才会触发成功,一旦有任何一个数组参数对象里面的 Promise 对象失败则立即触发该 Promise 对象的失败。
// promise1 、promise2 、 promise3 都成功才会调用成功函数,否则调用失败函数 Promise.all([promise1, promise2, promise3, ...]).then(成功函数, 失败函数)
let p1 = new Promise((resolve, reject) => {
resolve('p1')
})
let p2 = new Promise((resolve, reject) => {
resolve('p2')
})
let p3 = new Promise((resolve, reject) => {
reject('p3')
})
let pAll1 = Promise.all([p1, p2, p3]).then(value => {
console.log(value)
}, error => {
console.log(error) // p3
})
let pAll2 = Promise.all([p1, p2]).then(value => {
console.log(value) // (2) ["p1", "p2"]
}, error => {
console.log(error)
})
Promise.all() 返回一个新的 Promise, 只有所有的 Promise 都成功才成功, 只要有一个失败了就直接失败。
Promise.race
Promise.race() 方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。传入的参数为数组形式。
race 翻译过来大致就是“比赛”的意思。因此,第一个完成的 Promise 的结果状态就是最终的结果状态。
// 如果 promise1 为成功状态并先完成,那么最终将执行成功函数;如果 promise1 为失败状态并先完成,那么最终将执行失败函数。 Promise.race([promise1, promise2, promise3, ...]).then(成功函数, 失败函数)
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p1')
}, 1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p2')
}, 2000)
})
let p3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('p3')
}, 3000)
})
Promise.race([p1, p2, p3]).then(value => {
console.log(value) // p1
}, error => {
console.log(error)
})
Promise.allSettled
Promise.allSettled() 方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只有等到所有这些参数实例都返回结果,不管是 fulfilled 还是 rejected,包装实例才会结束。
该方法返回的新的 Promise 实例,一旦结束,状态总是 fulfilled,不会变成 rejected。状态变成 fulfilled 后,Promise 的监听函数接收到的参数是一个数组,每个成员对应一个传入 Promise.allSettled() 的 Promise 实例。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("hello")
}, 1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("error")
}, 1000)
})
let res = Promise.allSettled([p1, p2])
console.log(res) // Promise {<pending>}
手写Promise - 待完善
相关问题与题目
如何改变Promise的状态
Promise 状态的改变除了上面所说的从 pendding 变为 resolved 和 pendding 变为 rejected 之外,还有一种可以改变状态,那就是抛出异常,会从 pendding 就会变为 rejected。
let p = new Promise((resolve, reject) => {
throw new Error('error')
})
p.then(
value => {},
error => {
console.log(error) // Error: error
}
)
改变Promise状态和指定回调函数的谁先谁后
都有可能,一般情况下先指定回调函数然后再改变的状态,但是也可也先改变状态然后再指定回调函数
如下两种方法可以先改变状态然后再指定回调函数:
在执行器中直接调用 resolve() / reject()
添加 setTimeout 延迟更长的时间调用 .then()
// 先指定的回调函数,并保存当前指定的回调函数。然后改变的状态,再执行异步回调函数
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p1')
}, 1000)
})
p1.then(value => {
console.log(value)
}, error => {
console.log(error)
})
// 先改变的状态,然后指定回调函数,并异步执行回调函数
let p2 = new Promise((resolve, reject) => {
resolve('p2')
})
p2.then(value => {
console.log(value)
}, error => {
console.log(error)
})
// 先改变的状态,然后指定回调函数,并异步执行回调函数
let p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p3')
}, 1000)
})
setTimeout(() => {
p3.then(value => {
console.log(value)
}, error => {
console.log(error)
})
}, 1200)
.then()返回的新Promise的结果状态由什么决定
如果返回的是非 Promise 的任意值, 新 Promise 变为 resolved, value 为返回的值;
如果返回的是另一个新 Promise, 那么这个 Promise 的结果就会成为新 Promise 的结果 ;
如果抛出异常, 新 Promise 变为 rejected, error 为抛出的异常;
new Promise((resolve, reject) => {
resolve('hh')
}).then(value => {
console.log('demo1,' + value) // demo1,hh
}, error => {
console.log('demo1,' + error)
}).then(value => {
console.log('demo2,' + value) // demo2,undefined
}, error => {
console.log('demo2,' + error)
})
new Promise((resolve, reject) => {
resolve('hh')
}).then(value => {
console.log('demo1,' + value) // demo1,hh
return 1
}, error => {
console.log('demo1,' + error)
}).then(value => {
console.log('demo2,' + value) // demo2,1
}, error => {
console.log('demo2,' + error)
})
new Promise((resolve, reject) => {
resolve('hh')
}).then(value => {
console.log('demo1,' + value) // demo1,hh
return Promise.resolve('3')
}, error => {
console.log('demo1,' + error)
}).then(value => {
console.log('demo2,' + value) // demo2,3
}, error => {
console.log('demo2,' + error)
})
new Promise((resolve, reject) => {
resolve('hh')
}).then(value => {
console.log('demo1,' + value) // demo1,hh
return Promise.reject('4')
}, error => {
console.log('demo1,' + error)
}).then(value => {
console.log('demo2,' + value)
}, error => {
console.log('demo2,' + error) // demo2,4
})
new Promise((resolve, reject) => {
resolve('hh')
}).then(value => {
console.log('demo1,' + value) // demo1,hh
throw 5
}, error => {
console.log('demo1,' + error)
}).then(value => {
console.log('demo2,' + value)
}, error => {
console.log('demo2,' + error) // demo2,5
})
