ES6_Promise

Promise

Promise 对象有以下两个特点:

  1. 对象的状态不受外界影响。Promise 对象代表一个异步操作,有3种状态:Pending(进行中)、Fulfilled(已成功)和Rejected(已失败)。只有异步操作的结果可以决定当前是什么状态,任何其他操作都无法改变这个状态。

    在《ES6标准入门》一书中,用 Resolved 状态统一指 Fulfilled,本文参考之。

  2. 一旦状态改变就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变只有两种可能:

    Pending => Fufilled 和 Pending => Rejected。只要这两种情况发生,状态就凝固不变。这时就称为 Resolved(已定型)

在这里插入图片描述

Promise 的缺点:

  1. 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
  2. 如果不设置回调函数,Promise 内部抛出的错误不会反应到外部。
  3. 当处于Pending 状态时,无法得知目前进展到哪一阶段,刚刚开始还是即将完成。

如果某些事情不断地反复发生,一般来说,使用 Stream 模式是比部署 Promise 更好的选择。

.

基本用法

Promise 新建后就会立即执行,即 new Promise() 为同步代码。

Promise 构造函数接收一个函数作为参数,该函数的两个参数分别是 resolve 和 reject,它们也为两个函数。

reject 函数的参数通常是 Error 对象的实例,表示抛出的错误。

resolve 函数的参数除了正常的值外,还可能是另一个 Promise 实例。如:

var p1 = new Promise(function (resolve, reject) {
   // ... 
});

var p2 = new Promise(function (resolve, reject) {
    // ...
    resolve(p1);
});               

注意:此时 p1 的状态就会传递给 p2。即,p1的状态决定了p2的状态。如果p1的状态是 Pending ,那么 p2 的回调函数就会等待 p1的状态改变;如果 p1 的状态已经是 Resolved 或 Rejected ,那么p2 的回调函数将立即执行。

.

Promise.prototype.then()

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

then 方法第一个参数是 Resolved 状态的回调函数,第二个参数**(可选)**是 Rejected 状态的回调函数。

then 方法返回的是一个新的 Promise 实例,但是不是原来的那个Promise 实例。因此可以链式调用 then。

.

Promise.ptototype.catch()

catch 方法相当于是 then(null, rejection) 的别名,用于指定发生错误时的回调函数。

reject 方法的作用等同于抛出错误,catch 相当于 try-catch 中catch 块。

如果Promise 状态已经变成 Resolved,再抛出错误是无效的。如:

var promise = new Promise(function (resolve, reject) {
   	resolve('ok');
    throw new Error('test');
});

promise.then(function (value) { console.log(value) })
	.catch(function(error) { console.log(error) });
// ok

上面的代码中,Promise 在 resolve 语句后面抛出错误,并不会被捕获,等于没有抛出。

因为 Promise 的状态一旦改变,就会永久保持,不会再改变了。

Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。即,错误总是会被下一个catch 语句捕获,catch 可以捕获它之前的所有错误,但是在它之后的错误需要另一个 catch 来捕获了。如:

getJSON('/post/1.json').then(function (post) {
    return getJSON(post.commentURL);
}).then(function (comments) {
    // some code
}).catch(function (error) {
   // 处理前面 3 个 Promise 产生的错误 
}).then(function () {
   // 这里如果出错,将不会被捕获到了 
});

关于 catch 错误捕获,还有 外层代码错误捕获 和 Promise 的错误捕获 之间的关系。

.

Promise.all()

静态方法,Promise.all 方法用于将多个Promise 实例包装成一个 新的 Promise 实例。

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

Promise.all 参数 注意事项:

  1. Promise.all 方法接收一个数组作为参数,也可以不是数组,但是必须具有 Iterator 接口。
  2. p1 p2 p3 最终都是 Promise;若不是,就会先调用 Promise.resolve 方法,将参数转成 Promise 实例,再做处理。

p 的状态由 p1、p2、p3 决定,有如下两种情况:

  1. 只有 p1、p2、p3 的状态都变成 Fulfilled ,p的状态才会变成 Fulfilled,此时 p1、p2、p3 的返回值组成一个数组,传递给 p 的回调函数。
  2. 只要 p1、p2、p3 中有一个被 Rejected,p 的状态就变成 Rejected ,此时第一个被 Rejected 的实例的返回值会传递给p的回调函数 catch。

Promise.all 关于错误的捕获,注意:如果作为参数的 Promise 实例自身定义了 catch 方法,那么它被 rejected 时并不会触发 Promise.all() 的 catch 方法。

// p1 的状态即将为 resolved
const p1 = new Promise((resolve, reject) => {
  resolve('hello');  
})
.then(result => result)
.catch(e => e);

// p2 的状态即将为 rejected
const p2 = new Promise((resolve, reject) => {
    throw new Error('报错了');
})
.then(result => result)
.catch(e => e);

// Promise.all
Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));

// ['hello', Error: 报错了]

​ 上面的代码中,p1 会 resolved ,p2 首先会 rejected,但是p2 有自己的 catch 方法,该方法返回的是一个新的Promise 实例, p2 实际上指向的是这个实例。该实例执行完 catch 方法后也会变成 resolved,导致 Promise.all() 方法参数里面的两个实例都会 resolved,因此会调用then 方法指定的回调函数,而不会调用 catch 方法指定的回调函数。

​ 如果p2 没有 catch 方法,就会调用 Promise.all()的 catch 方法。

.

Promise.race()

静态方法,也是将多个 Promise 实例包装成一个新的Promise 实例。

var p = Promise.race([p1, p2, p3]);

race 有赛跑的意思:只要 p1、p2、p3 中有一个实例率先改变状态,p 的状态就跟着改变。那个率先改变的 Promise 实例的返回值就传递给 P 的回调函数。

Promise.race 的参数 如果不是 Promise 实例,也会和 Promise.all 一样,先用 Promise.resolve 转换成 Promise 对象,再处理。

.

Promise.resolve()

将现有对象转为 Promise 对象。

Promise.resolve('foo');
// 等价于
new Promise(resolve => resolve('foo'));

注意:对于 Promise.resolve 方法的参数,分以下4种情况:

  1. 参数是一个 Promise 实例

    如果参数是 Promise 实例,那么 Promise.resolve 将不做任何修改,原封不动地返回这个实例。注意,此时并不会改变传入的 Promise 对象的状态。

    const p1 = new Promise((resolve, reject) => {
        console.log('进来了');
        if(Math.random() > 0.5) {
            resolve();
        } else {
            reject();
        }
    });
    
    const p2 = Promise.resolve(p1).then(() => {
        console.log('成功了');
    }).catch(() => {
        console.log('失败了');
    });
    // 打印的结果不一定
    
  2. 参数是一个 thenable 对象(指具有 then 方法的对象

    Promise.resolve 方法会将这个对象转为 Promise 对象,然后立即执行 thenable 对象的 then 方法。

    thenable 对象的 then 方法执行后,对象 p1 的状态就变为 resolved。

    const thenable = {
        then(resolve, reject) {
            resolve(42);
        }
    };
    
    const p4 = Promise.resolve(thenable).then((val) => {
        console.log(val);
    }).catch((e) => {
        console.log(e);
    });
    // 42
    
  3. 参数不是具有 then 方法的对象或根本不是对象

    如果参数是一个原始值,或者是一个不具有 then 方法的对象,那么Promise.resolve 方法返回一个新的 Promise 对象,状态为 Resolved。

    const p5 = Promise.resolve({ a: true });
    p5.then((obj) => {
        console.log(obj);
    }).catch((e) => {
        console.log(e);
    })
    // {a: true}
    
  4. 不带有任何参数

    Promise.resolve 方法允许不带有参数,而直接返回一个状态为 Resolved 的Promise 对象。

    var p = Promise.resolve();
    p.then(() => {
       console.log('成功'); 
    }).catch(() => {
        console.log('失败');
    });
    // 成功
    

综上所述: Promise.resolve 返回值是一个 Promise 对象,但是不一定状态都是 Resolved ,如果传入的参数是一个Promise 对象,则状态不定,其他参数情况下状态均为 Resolved

.

Promise.reject()

Promise.reject(reason) 方法也会返回一个新的 Promise 实例,状态为 Rejected。

var p = Promise.reject('出错了');
// 等同于
var p = new Promise((resolve, reject) => reject('出错了'));

注意:Promise.reject() 方法的参数会原封不动地作为 reject 的理由变成后续方法的参数。这点与 Promise.resolve 方法不一致。

const thenable = {
    then(resolve, reject) {
        reject('出错了');
    }
};

Promise.reject(thenable).catch(e => {
   console.log(e); 
});
// { then: [Function: then] }

.

阿里巴巴前端笔试题:关于Promise,下列说法正确的是:

a.Promise.resolve 返回一个 Promise 对象,状态为 fufilled

b.Promise.rejected 返回一个 Promise 对象,状态为 rejected

c. Promise.all 中当所有 Promise 为 fufilled 或 rejected 时,状态为 fufilled

d.Promise.race 中当有一个 Promise 为 fufilled 时,状态为 fufilled

e.Promise.all 的所有参数都要是Promise 对象

f.Promise.race 的所有参数都要是Promise 对象

b d

如有错漏,欢迎补充讨论!

发布了51 篇原创文章 · 获赞 27 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_39446719/article/details/89214958