Promise英文翻译过来是诺言、承诺的意思
顾名思义,Promise的潜在含义是:
promise代表的是还没发生的事而在Javascript中的Promise代表的意义是类似的,对于异步操作(网络请求、文件I/O等)这些事情在完成之前无法确定其状态,在完成的时候要么成功要么失败,Promise会在完成的时候通知你。
上面是Promise的定义,Promise是一个表示异步事件处理完成的对象,我们看看传统的异步操作是怎样的:
function successCallback(result) {
console.log('Result is ready: ', result);
}
function failureCallback(error) {
console.log('Error on async request: ', error);
}
requestData(options, sucessCallback, failureCallback)在传统的异步操作下,整个接口的定义实现方式,没有一个清晰的定义,不同的人去写,接口的定义方式不一样。
function successCallback(result) {
console.log('Result is ready: ', result);
}
function failureCallback(error) {
console.log('Error on async request: ', error);
}
requestData(options).then(successCallback).catch(failureCallback)在Promise中,抽象出了异步操作成功(then)的接口和失败的接口(catch/reject),并且支持链式调用,在传统的callback的实现中,如果下一个异步操作依赖于上一个操作,很容易写出callback hell的这种代码,对于代码的阅读和维护带来麻烦。
Promise对象对象是一个代理对象,被代理的值表示一个异步操作,在创建的时候,对于最终异步操作的返回结果是未知的,Promise允许为异步操作的成功和失败分别绑定相应的处理方法,让异步方法可以像同步方法一样返回值,但并不是立即返回最终的执行结果,而是一个代理了未来出现的结果的Promise对象,Promise有以下几种状态:
pending:初始状态,创建promise之后,执行还没结束的时候fulfilled:异步操作成功rejected:异步操作失败
如上图,在promise创建后,所处的状态为pending状态,执行成功或失败的这个过程叫settled,settled之后,promise由pending状态转换到fulfilled或rejected状态,并执行相应的回调。
我们首先来看看Promise提供的方法:
常见的方式是通过Promise的构造函数得到Promise的实例:
function executor(resolve, reject) {
const r = asyncWork();
r.on('success', (s) => {
resolve(s);
})
r.on('error', (e) => {
reject(e);
})
}
const p = Promise(executor)如上Promise的构造函数接收一个executor函数为参数,这个executor一般来说是一个异步操作,在生成实例的时候会被执行,在执行成功的时候调用resolve,失败的时候调用reject。
Promise.prototype.then(onFulfilled?, onRejected?),在promise resolve的时候onFulfilled会被调用,reject的时候onReject会被调用,这两个参数是可选的,如果你只想对异常进行处理的话,可以使用promise.then(undefined, onRejected)Promise.prototype.catch(onRejected),catch方法会在promise reject的时候被调用。Promise.prototype.finally(onFinally),向当前promise添加一个回调函数,无论当前promise的状态是完成还是失败都会被调用Promise.resolve(value),返回一个由给定value决定的promise对象;如果这个value可以是一个thenable的对象(带有then方法的对象),最终返回的promise对象的状态由then方法执行决定;否则的话,返回的promise对象状态为fulfilled,并且将该值传给对应的then方法,如果你不知道一个值是否是Promise对象,使用Promise.resolve(value)来返回一个Promise对象,这样就能将该value以Promise对象的形式使用。Promise.reject(reason),返回一个执行状态为rejected的Promise对象,并将错误信息给到对应的处理函数Promise.race(iterable),当iterable中的任意一个子promise成功或者失败后,父promise会使用这个子promise的结果,传给父promise绑定的回调上Promise.all(iterable),这个方法返回一个promise对象,只有iterable中所有的promise执行成功的时候才会触发成功,一旦由任何一个执行失败都会触发要返回这个promise额失败,最终iterable的返回结果和iterable的顺序一致。promise是支持链式调用的:
Promise.resolve({
then: (resolve, reject) => {
resolve(1);
}
})
.then((r) => {
console.log(r)
})
.then(() => {
console.log(2)
})
.finally(() => {
console.log(3)
})
.then(() => {
console.log(4)
}) // use `catch`
new Promise((resolve, reject) => {
console.log('Init')
resolve()
})
.then(() => {
throw new Error('error') // {A}
})
.then(() => { // {B}
console.log('123');
})
.catch(() => {
console.log('Error was caught!')
})
.then(() => {
console.log('End')
})
// use reject
new Promise((resolve, reject) => {
console.log('Init')
resolve()
})
.then(() => {
throw new Error('error')
})
.then(() => {
console.log('End')
}, () => {
console.log('Error was caught!')
})promise在处理错误的时候,可以通过Promise.ptototype.catch或者是注册的reject方法来处理错误,在{A}行处,抛出了错误,这里promise的状态会变为rejected,会调用对应的回调函数,在{A}到.catch之间的promise链会被打断。
function delay(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms);
})
}我们在使用setTimeout的时候,setTimeout执行的函数如果执行发生了错误,并且在函数的实现中并没有做Error Handling,函数执行发生错误的时机我们并不知道,如果使用上面基于promise包裹之后的timeout,我们是可以明确知道错误发生的时机的。
promise创建之后,会等待异步操作的执行,如果异步操作的时间很长的话,这个promise一直处于 pending状态,对于用户来说,页面会一直停留在loading的状态,显然,用户体验并不好,因此,对于这种情况,我们需要提供可以在超时之后,取消promsie的机制:
function delayPromise(ms) {
return delay(ms).then(() => {
console.error('Operation is timeout!');
})
}
function timeoutPromise = (asyncFn, ms) {
return Promise.race([
new Promise(asyncFn),
delayPromise(ms)
]);
}如上我们基于Promise.race实现了超时promise。
兴趣遍地都是,坚持和持之以恒才是稀缺的