Promise总结| 8月更文挑战

304 阅读7分钟

1.Es6加入promise的原因

前置知识:

  • 异步操作的必要性:

在同步操作(前一条指令完成后一条才可以执行)中,耗时很长的操作会造成页面冻结,所以把计算量大的操作变为异步操作很必要。

  • 异步操作以往解决方案:

1.事件监听:

eg:点击事件-document.click(回调函数)。

缺点:如果错过了事件,再去监听,是得不到结果的。

2.回调函数:

缺点:容易造成回调地狱;代码不好维护;可读性差;

2.Promise对象

2.1什么是Promise?

Promise是ES6异步编程的一种解决方案,比传统的方案(回调函数和事件监听)更加合理和强大。

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

2.2Promsie的作用

  • 将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。
  • 将异步操作队列化,按照期望的顺序执行,返回符合预期的结果。
  • 可以在对象之间传递和操作promise,帮助我们处理队列。

2.3Promise语法

let p1= new Promise(resolve, reject) =>//....异步操作
    if(/*异步操作成功*/){
        resolve(value);
    } else {
        reject(error);
    } } )
    p1.then(function(value) {
        // resolve状态的回调函数
    }, function(error) {
        //reject状态的回调函数
    })

2.3Promise特点

  • 对象的状态不受外界影响

Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有resolve和reject函数,可以改变状态,任何其他操作都无法改变这个状态。

  • 一旦状态改变,就不会再变,任何时候都可以得到这个结果
  • Promise 新建后立即执行
  • Promise构造函数里的代码是同步执行的,而Promise.then()是异步的。
  • 调用resolve或reject并不会终结 Promise 的参数函数后面代码的执行,如果有return会终止。

2.4 resolve、reject的参数

正常值(非promise的值): 将值传递给then()中的回调函数。

另一个promise实例对象 (如下图):

状态传递: 这时p1的状态就会传递给p2,p1的状态决定了p2的状态。如果p1的状态是pending,那么p2的回调函数就会等待p1的状态改变;如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行。

promise.reject参数是promise对象.png

3. Promise原型上的方法

3.1 Promise.prototype.then()

参数:

resolved状态的回调函数【可选】

rejected状态的回调函数【可选】

返回值:

一个新的Promise实例---因此可以采用链式写法,即then方法后面再调用另一个then方法。

作用:

为 Promise 实例添加状态改变时的回调函数。

Promise值穿透

Promise.then() 或者 .catch()的参数期望是函数,传入非函数则会发生值穿透。

当我们不在 then 中放入参数或者放入不是函数的参数,例:promise.then().then(),promise.then(1),promise.then(Promise.resolve('foo'))那么其后面的 then 依旧可以得到之前 then 返回的值,这就是所谓的值的穿透。(这里可以理解为只要then()里的参数不是函数,则直接将这个then()忽略掉。)

Promise.resolve('foo')
    .then(Promise.resolve('bar'))
    .then(res=>{ console.log(res) })
    // 'foo'
Promise.resolve('foo')
    .then(()=>{ return Promise.resolve('bar') })
    .then(res=>{ console.log(res) })
    // 'bar'
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
// 1
Promise.resolve(1)
.then(function(){return 2})
.then(Promise.resolve(3))
.then(console.log)
// 2
Promise.resolve(1)
.then(function(){return 2})
.then(function(){
   return Promise.resolve(3)
})
.then(console.log)
// 3

Promise.then()的链式调用

在我们使用 Promise 的时候,当 then 函数中 return 了一个值,不管是什么值,我们都能在下一个 then 中获取到,这就是所谓的then 的链式调用。

Promise.reject()和Promise.prototype.catch()优先问题

promise.reject.png 第一个then接受了两个函数,第二个是失败时候的回调,由于第一个then里面没有抛出Error,则第二个then状态是resolve。 promise.reject02.png 当同时存在失败回调状态函数和catch函数时,会走失败回调状态函数。 promise.reject03.png 当then方法中没有指定失败的回调函数时,使用.catch会默认为没有指定失败回调函数的.then指定失败回调函数。 promise.reject04.png catch的异常穿透是一层层传递下来的并非一次失败状态直接传递到catch。

3.2 Promise.prototype.catch()

Promise.prototype.catch()方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。

3.3 Promise.prototype.finally()

finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。

参数: 没有参数的回调函数。

实现:

Promise.prototype.finally = function (callback) {
    let P = this.constructor;
    return this.then( value => P.resolve(callback()).then(() => value),
    reason => P.resolve(callback()).then(() => { throw reason }) );
};

4. Promise对象方法

4.1 Promise.resolve()

作用:返回一个状态为resolved的 Promise 实例。回调函数会立即执行。

参数 返回值:

  • promise实例 --- 不做任何修改、原封不动地返回这个实例。
  • thenable对象(具有then方法的对象) --- 将这个对象转为 Promise 对象,然后就立即执行thenable对象的then()方法。
  • 不是具有then()方法的对象,或根本就不是对象 --- 返回一个新的 Promise 对象,状态为resolved,并将这个参数传给传给状态的回调函数。
  • 不带有任何参数 --- 直接返回一个resolved状态的 Promise 对象。

4.2 Promise.reject()

作用: 返回一个状态为rejected的 Promise 实例。回调函数会立即执行。

Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。

4.3 Promise.try()

作用: 让同步函数同步执行,异步函数异步执行,可以统一用promise.catch()捕获所有同步和异步的错误。

const f = () => console.log('now');
Promise.try(f);
console.log('next');
// now
// next

4.4 Promise.all() --- 全都完成就返回完成,有一个失败就返回失败

作用: 将多个 Promise 实例,包装成一个新的 Promise 实例。

参数: 一个promise实例的数组

  • 如果不是,就会先调用Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。
  • 参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。

返回值:

const p = Promise.all([p1, p2, p3]);

p的状态由p1、p2、p3决定,分成两种情况。

(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

4.5 Promise.any() --- 有一个完成就返回完成,全部失败就返回失败

作用: 将多个 Promise 实例,包装成一个新的 Promise 实例。

参数: 一个promise实例的数组

注意: Promise.any()跟Promise.race()方法很像,只有一点不同,就是Promise.any()不会因为某个 Promise 变成rejected状态而结束,必须等到所有参数 Promise 变成rejected状态才会结束。

返回值:

const p = Promise.any([p1, p2, p3]);

(1)只要p1、p2、p3之中有一个被fulfilled,p的状态就变成fulfilled,此时第一个被fulfilled的实例的返回值,会传递给p的回调函数。

(2)只有p1、p2、p3的状态都变成rejected,p的状态才会变成rejected,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

4.6 Promise.allSettled() --- 全都结束后返回成功

作用: 将多个 Promise 实例,包装成一个新的 Promise 实例。

参数: 一个promise实例的数组

返回值: 等到所有这些参数实例都返回结果(不管是fulfilled还是rejected)包装实例才会结束。

一旦结束,状态总是fulfilled,不会变成rejected。状态变成fulfilled后,Promise 的监听函数接收到的参数是一个数组,每个成员都是一个对象,对应传入Promise.allSettled()的两个 Promise 实例。每个对象都有status属性,该属性的值只可能是字符串fulfilled或字符串rejected。fulfilled时,对象有value属性,rejected时有reason属性,对应两种状态的返回值。。

注意: 当我们不关心异步操作的结果,只关心这些操作有没有结束时,Promise.allSettled()方法就很有用。

4.7 Promise.race() --- 有一个改变状态就返回第一个的状态

作用: 将多个 Promise 实例,包装成一个新的 Promise 实例。

参数: 一个promise实例的数组

返回值: 只要参数数组实例对象之中有一个实例率先改变状态,返回值的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给回调函数。

参考:

es6.ruanyifeng.com/#README

www.cnblogs.com/xjt31/p/140…