1. Promise 的含义
Promise 是异步编程的一种解决方案,比传统的解决方案 – 回调函数和事件更合理、更强大。
1.1 什么是 Promise
简单来说就是一个容器,里面保存着某个未来才会结束的事件(也就是异步操作)的结果。从语法上来讲,Promise 是一个对象,从它可以获取异步操作的消息,它提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise 有两个特点:
1.1.1、对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态、任何其他操作都无法改版这个状态。
1.1.2、一旦状态改版,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只存在两种可能:从 pending 变为 fulfilled 和 从 pending 变为 rejeced。只要这两种情况发生,状态就终止,不会再变了并一直保持这个结果。这时就称为 resolved(已定型)。如果改版已经发生了,即使再对 Promise 对象添加回调函数,也会立即得到这个结果。如果你错过了再想去监听,是得不到结果的。
1.1.3、有了 Promise 对象,就可以将异步操作以同步操作的流程显示出来,这样就避免了层层嵌套的回调函数。Promise 对象提供统一的接口,使得控制异步操作更加容易。
1.1.4、Promise 也有一些缺点,就是无法取消 Promise,一旦建立就会立即执行,无法中途取消。如果不设置回调函数,Promise 内部抛出的错误不会反应到外部。另外如果处于 pending 状态时,是无法知道现在到了哪一个阶段。
2. 基本用法
Promise 对象是一个构造函数,用来生成 Promise 实例
const promise = new Promise((reolve, reject) => {if (// 异步操作成功) {resolve(val)
}else{reject(val)
}
})
Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 和 reject。
resolve:,将 Promise 对象的状态从『未完成』变为『成功』(pending => resolved),在 异步操作成功时 调用,并将异步操作的结果作为参数传递出去。
reject:将 Promise 对象的状态从『未完成』变为『失败』(pending => rejected), 在 异步操作失败时 调用,并将异步操作的结果作为参数传递出去。
Promise 实例生成以后,可以用 then 方法分别指定 resolved 状态和 rejected 状态的回调函数。
promise.then((val) => {// success},(err) => {// failure})
then 方法可以接受两个回调函数作为参数。(第二个函数可选,这两个函数都接受 Promise 对象传出的值作为参数)
1、第一个回调函数在 Promise 对象的状态变为『resolved』时调用。
2、第二个回调函数在 Promise 对象的状态变为『rejected』时调用。
实例:function timeout(ms) {retrun new Promise((resolve, reject) => {setTimeout(resolve, ms, 'done')
})
}
timeout(100)
.then((v) => {console.log(v)
})
上面代码中,timeout 方法返回一个 Promise 实例,表示一段时间以后才会发生的结果,过了 ms 时间后,Promise 状态变为『resolved』然后就会触发 then 方法绑定的回调函数。
Promise 建立后就会立即执行
let promise = new Promise((resolve, reject) => {console.log('Promise')
resolve()})
promise
.then(() => {console.log('resolved')
})
console.log('hh')
// Promise
// hh
// resolved
Promise 建立后立即执行,首先输出「Promise」然后执行 promise 的 then 函数,然后首先执行同步任务 输出 hh 在执行 then 方法的回调函数输出 resolved
如果调用 resolve 函数和 reject 函数时带有参数,那么它们的参数会被传递给回调函数。reject 函数的参数通常是 Error 对象的实例,表示抛出的错误。resolve 函数的参数除了正常的值以外,还有可能是一个 Promise 实例。resolve 实在成功的时候调用,reject 是在失败的时候调用。
const p1 = new Promise(function (resolve, reject) {// ...});
const p2 = new Promise(function (resolve, reject) {
// ...
resolve(p1);
})
上述代码中:p1 和 p2 都是 Promise 的实例,但是 p2 的 resolve 方法将 p1 作为参数,即一个异步操作的结果返回是另一个异步操作。
注意:p1 的状态就会传递给 p2,p1 的状态决定了 p2 的状态。如果 p1 的状态是 pending,那么 p2 的回调函数就会等待 p1 的状态改变;如果 p1 的状态已经是 resolved 或者 rejected,那么 p2 的回调函数会立即执行。
一般来说,调用 resolve 或 reject 以后,Promise 的进程就就结束了,后续操作应该放到 then 方法里,而不是直接写在 resolve 或 reject 的后面。另外最后在它们之前加上 return 语句。
3. Promise.prototype.then()
Promise 实例具有 then 方法,then 方法是定义在原型对象 Promise.prototype 上的。它的作用是为 Promise 实例添加状态改变时的回调函数。then 的第一个参数是 resolved 状态的回调函数,第二个参数是 rejected 状态的回调函数。
then 方法返回的是一个新的 Promise 实例,不是原来那个,因此可以使用链式写法。.then().then()
a().then((j) => {retrun j}).then((i) => {console.log(i)
},(err)=>{console.log(err)
})
上面 第一个 then 方法指定的回调函数,返回的是另一个 Promise 对象。这时,第二个 then 方法指定的回调函数,就会等这个新的 Promise 对象状态发生变化,如果变为 resolved,就调用第一个回调函数,如果状态变为 rejected,就调用第二个回调函数。
4. Promise.prototype.catch()
Promise.prototype.catch 方法是 .then(null, rejecton) 或 .then(undefined, rejection)的别名,用于指定发生错误时的回调函数。
a().then((p) => {// success}).catch((err) => {console.log('err')
})
如果对象的状态变为 resolved, 则会调用 then 方法指定的回调函数 success, 如果异步操作抛出错误,状态就会变为 rejected, 就会调用 catch 方法指定的回调函数处理这个错误。如果 then 方法指定的回调函数,在运行中抛出错误,也会被 catch 方法捕获。
另外 reject 方法的作用等同于抛出错误
如果 Promise 状态已经变成 resolved,再抛出错误是无效的。因为状态一旦改版,就永远保持,不会再变了。而且 Promise 的错误有『冒泡』的性质,会一直向后传递,直到被捕获位置,它的错误总会被下一个 catch 语句捕获。
建议:Promise 对象后面要跟 catch 方法,这样可以处理 Promise 内部发生的错误。catch 方法返回的还是一个 Promise 对象,因此后面还可以接着调用 then 方法。
注意: catch 函数中的方法发生错误,如果后面没有别的 catch 方法,那么错误将不会被捕获,如果 catch 后面 还有 catch,第二个 catch 将会捕获前一个 catch 方法抛出的错误。
5. Promise.prototype.finally()
finally 方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
以上,不管 promise 最后的状态,都会执行 finally 方法指定的函数。
finally 方法的回调函数不接受任何参数,所以就无法知道之前 Promise 状态到底是 fulfilled 还是 rejected。所以在 finally 方法里面的操作,是与之前状态无关的而且不依赖于 Promise 的执行结果。
6. Promise.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 实例。)
Promise.all 的状态有两种情况:
1、如果 p1 p2 p3 的状态都变成了 fulfilled,p 的状态才是 fulfilled,这时候返回一个 p1 p2 p3 返回值组成的数组,传递给 p 的回调函数。
2、如果 p1 p2 p3 中任一一个被 rejected,p 的状态就变成了 rejected,这时候返回的是第一个被 rejected 实例的返回值,传递给 p 的回调函数。
注意 ,如果作为参数的 Promise 实例,自己定义了 catch 方法,那么它一旦被 rejected,并不会触发 Promise.all() 的 catch 方法。而是触发自己定义的 catch 方法。
7. Promise.race()
Promise.race 方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3]);
与 Promise.all 的区别就是 p1 p2 p3 中一个实例改变状态,那么 p 的状态就跟着改变了,返回值为最先返回那个 Promise 实例的返回值。
8. Promise.resolve()
将现有对象转为 Promise 对象。
1、如果参数是一个 Promise 实例
那么将不做任何修改。
2、参数是一个 thenable 对象(具有 then 方法的对象)
将这个对象转为 Promise 对象,然后立即执行 thenable 对象的 then 方法
3、参数不是具有 then 方法的对象,或根本不是对象
返回一个新的 Promise 对象,状态为 resolved
4、不带任何参数
直接返回一个 resolved 状态的 Promise 对象
9. Promise.reject()
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为 rejected。回调函数立即执行。
关注公众号【小夭同学】