- A+
Promise是一个JS的异步编程解决方案,解决了传统异步编程回调地狱的问题。
Promise有三种状态:
-
pending(进行中)
-
fulfilled(已完成)
-
rejected(已失败)
只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
其中pending 为初始状态,状态的变化只有两种:
-
pending --- fulfilled(异步完成)
-
pending --- rejected(异步失败)
且一旦状态改变,状态就会凝固,不会在变化了,这就导致了 Promise 一旦建立就会立即执行,无法取消。
Promise 的基本用法
ES6 规定 Promise 是一个构造函数,用来生成 Promise 对象实例。
const promise = new Promise(function(resolve,reject){ // 异步操作 if(success){ //异步操作成功 resolve(value); } else{ //异步操作失败 reject(err); } })
Promise 构造函数接收的参数是一个函数,改函数有两个有JS引擎指定的函数: resolve 函数 和 reject函数
-
resolve 函数有两个作用:
-
将 Promise 状态由 pending -- fulfilled (等待态 -- 成功态)
-
将异步操作成功的结果value 作为参数传递出去 (由后面讲的 then 方法接收)
-
reject 函数有两个作用:
-
将Promise 状态 pending -- rejected (等待态 -- 失败态)
-
将异步操作失败的错误信息 err 作为参数传递出去。 (由后面讲到的then / catch 方法接收)
Promise 的三个实例方法 then catch finally
-
1、Promise.prototype.then()
Promise 实例具有 then方法,也就是说then方法是定义在原型对象上的。
Promise 实例生成后,可以用then方法分别指定 resolve状态和rejected状态的回调函数:获取Promise 内部的异步操作状态。
promise.then({ function(value){ console.log(value) }, //异步操作成功时(fulfilled态)调用 function(err){ console.log(err) } //异步操作失败时(rejected态)调用})
then 方法可以接收两个回调函数作为参数:
-
第一个回调函数在Promise 实例变成 fulfilled 时调用,并获取 resolve 函数传递的参数 value
-
第二个回调函数在Promise 实例变成rejected时调用,并获取 reject 函数传递的参数 err
then 方法的返回值是一个新的promise 对象,因此可以 .then 可以链式调用。
-
2、Promise.prototype.catch()
Promise 实例的 catch 方法用于指定发生错误时的回调函数,是 .then(null,rejection)的语法糖。
promise.then(function(val){ console.log(val) //异步操成功败时(rejected态)调用}).catch(function(err){ console.log(err) //异步操作失败时(rejected态)调用})
上面代码中,如果 Promise 对象状态变为 fulfilled,则会调用then方法指定的回调函数;
如果异步操作抛出错误,状态就会变为 rejected ,就会调用 catch 方法指定的回调函数。
另外,then方法指定的回调函数,如果运行抛出错误,也会被catch 方法捕获。
promise.then(val => console.log("fulfilled:",val)) .catch(err => console.log("rejected:",err))// 等价于promise.then(val => console.log("fulfilled:",val)) .then(null,err => console.log("rejected:",err))
如果 Promise 状态已经变成resolved , 再抛出错误时无效的,因为 Promise 的状态一旦改变,就永久保持该状态,不会在变了。
Promise 对象的错误具有冒泡性质,会一直向后传递,直到被捕获为止,也就是说错误总会被下一个catch 语句捕获。
-
3、Promise.prototype.finally()
Promise
实例的 finally
方法用于指定不管状态最终如何,都会执行的函数。是 .then(function,function)
(function相同)的语法糖。
promise.finally(message => console.log("状态变化了",message))// 等价于promise.then( message => console.log("状态变化了",message), message => console.log("状态变化了",message) )// 无论成功还是失败都会执行
Promise 的两个静态方法 all 和 race
Promise.all(arr) 方法是挂载在Promise构造函数的静态方法,它传入参数为一个Promise对象数组arr,返回值为一个Promise实例:
-
该实例会在Promise对象数组内所有对象的状态变为 fulfilled 时调用内部的 resolve函数;
-
该实例在Promise对象数组内任意对象的状态变为rejected时调用 reject函数(reject 函数的参数为第一个错误的promise 对象的err)
有点类似于js里的与操作(&&): 所有表达式为真时返回真,任意表达式为假时返回假。
let p1 = new Promise((resolve,reject)=>{ resolve('p1-success'), }) let p2 = new Promise((resolve,reject)=>{ resolve('p2-success'), }) let p3 = new Promise((resolve,reject)=>{ reject('p1-error'), }) Promise.all([p1,p2,p3]).then(val=>{ console.log(val) }).catch(err=>{ console.log(err) })//输出 p1-error
注意:Promise.all() 获得的成功结果的数组里面的数据顺序和 Promise.all() 接收到的数组顺序是一致的。即p1结果在前,即便p1的结果获取比p2要晚,这带来了一个绝大的好处:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用 Promise.all() 毫无疑问可以解决这个问题。
Promise.race()
Promise.race(arr)
方法返回一个 promise
实例,一旦arr
中的某个promise
对象解决或拒绝,返回的 promise
就会解决或拒绝。
顾名思义,Promise.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])
里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
let p1 = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve('p1-success') },1000) }) let p2 = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve('p2-success') },500) }) let p3 = new Promise((resolve,reject)=>{ setTimeout(()=>{ reject('p3-error') },1000) }) Promise.race([p1,p2,p3]).then(val=>{ console.log(val) }).catch(err=>{ console.log(err) })//输出 p2-success