美文网首页
ES6 Promise

ES6 Promise

作者: Cherry丶小丸子 | 来源:发表于2022-12-21 16:32 被阅读0次

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大

ES6 规定,Promise 对象是一个构造函数,用来生成 Promise 实例

1、Promise 的特点
  • 对象的状态不受外界影响,有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)
  • 一旦状态改变,就不会再变,任何时候都可以得到这个结果,只有两种可能:从 pending 变为 fulfilled 和从 pending 变为 rejected
2、Promise 的基本用法
const promise = new Promise(function(resolve, reject) {
    // ... some code

    if (/* 异步操作成功 */){
        resolve(value);
    } else {
        reject(error);
    }
});

resolve 函数的作用是,将 Promise 对象的状态从 “未完成” 变为 “成功”(即从 pending 变为 resolved)
reject 函数的作用是,将 Promise 对象的状态从 “未完成” 变为 “失败”(即从 pending 变为 rejected)

Promise实例生成以后,可以用 then 方法分别指定 resolved 状态和 rejected 状态的回调函数

promise.then(function(value) {
    // success
}, function(error) {
    // failure
});

then 方法可以接受两个回调函数作为参数。第一个回调函数是 Promise 对象的状态变为 resolved 时调用,
第二个回调函数是 Promise 对象的状态变为 rejected 时调用,这两个函数都是可选的,不一定要提供

Promise 新建后就会立即执行

let promise = new Promise(function(resolve, reject) {
    console.log('Promise');
    resolve();
});

promise.then(function() {
    console.log('resolved.');
});

console.log('Hi!');

// Promise
// Hi!
// resolved

如果调用 resolve 函数和 reject 函数时带有参数,那么它们的参数会被传递给回调函数。reject 函数的参数通常是 Error 对象的实例,表示抛出的错误;resolve 函数的参数除了正常的值以外,还可能是另一个 Promise 实例,比如像下面这样

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 的参数函数的执行

new Promise((resolve, reject) => {
    resolve(1);
    console.log(2);
}).then(r => {
    console.log(r);
});
// 2
// 1

上面代码中,调用 resolve(1) 以后,后面的 console.log(2) 还是会执行,并且会首先打印出来。
这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。

一般来说,调用 resolve 或 reject 以后,Promise 的使命就完成了,后继操作应该放到 then 方法里面,而不应该直接写在 resolve 或 reject 的后面。所以,最好在它们前面加上 return 语句,这样就不会有意外

new Promise((resolve, reject) => {
    return resolve(1);
    // 后面的语句不会执行
    console.log(2);
})
3、Promise.prototype.then()

Promise 实例具有 then 方法,也就是说,then 方法是定义在原型对象 Promise.prototype 上的
then 方法返回的是一个新的 Promise实例(注意,不是原来那个 Promise 实例)。因此可以采用链式写法,即 then 方法后面再调用另一个 then 方法

getJSON("/posts.json").then(function(json) {
    return json.post;
}).then(function(post) {
    // ...
});

上面的代码使用 then 方法,依次指定了两个回调函数。第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数

采用链式的 then,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个 Promise 对象(即有异步操作),这时后一个回调函数,就会等待该 Promise 对象的状态发生变化,才会被调用

getJSON("/post/1.json").then(function(post) {
    return getJSON(post.commentURL);
}).then(function (comments) {
    console.log("resolved: ", comments);
}, function (err){
    console.log("rejected: ", err);
});

上面代码中,第一个 then 方法指定的回调函数,返回的是另一个 Promise 对象。这时,
第二个 then 方法指定的回调函数,就会等待这个新的 Promise 对象状态发生变化。
如果变为 resolved,就调用第一个回调函数,如果状态变为 rejected,就调用第二个回调函数
4、Promise.prototype.catch()

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

getJSON('/posts.json').then(function(posts) {
    // ...
}).catch(function(error) {
    // 处理 getJSON 和 前一个回调函数运行时发生的错误
    console.log('发生错误!', error);
});

上面代码中,getJSON() 方法返回一个 Promise 对象,如果该对象状态变为 resolved,则会调用 then() 方法指定的回调函数;
如果异步操作抛出错误,状态就会变为 rejected,就会调用 catch() 方法指定的回调函数,处理这个错误。
另外,then() 方法指定的回调函数,如果运行中抛出错误,也会被 catch() 方法捕获
p.then((val) => console.log('fulfilled:', val))
    .catch((err) => console.log('rejected', err));

// 等同于
p.then((val) => console.log('fulfilled:', val))
    .then(null, (err) => console.log("rejected:", err));

一般来说,不要在 then() 方法里面定义 Reject 状态的回调函数(即 then 的第二个参数),总是使用 catch 方法

// bad
promise.then(function(data) {
    // success
}, function(err) {
    // error
});

// good
promise.then(function(data) {
    // success
}).catch(function(err) {
    // error
});
5、Promise.prototype.finally()

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

promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});

上面代码中,不管 promise 最后的状态,在执行完 then 或 catch 指定的回调函数以后,都会执行 finally 方法指定的回调函数
6、Promise.all()

Promise.all() 方法用于将多个 Promise 实例,包装成一个新的 Promise 实例

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

只有 p1、p2、p3 的状态都变成 fulfilled,p 的状态才会变成 fulfilled,此时 p1、p2、p3 的返回值组成一个数组,传递给 p 的回调函数
只要 p1、p2、p3 之中有一个被 rejected,p 的状态就变成 rejected,此时第一个被 reject 的实例的返回值,会传递给 p 的回调函数
7、Promise.race()

Promise.race() 方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例

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

只要 p1、p2、p3 之中有一个实例率先改变状态,p 的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给 p 的回调函数
8、Promise.allSettled()

Promise.allSettled() 方法接受一个数组作为参数,数组的每个成员都是一个 Promise 对象,并返回一个新的 Promise 对象

Promise.allSettled([
    fetch('/api-1'),
    fetch('/api-2'),
    fetch('/api-3'),
]);

只有等到参数数组的所有 Promise 对象都发生状态变更(不管是 fulfilled 还是 rejected),返回的 Promise 对象才会发生状态变更
9、Promise.any()
Promise.any([
    fetch('https://v8.dev/').then(() => 'home'),
    fetch('https://v8.dev/blog').then(() => 'blog'),
    fetch('https://v8.dev/docs').then(() => 'docs')
]).then((first) => {  // 只要有一个 fetch() 请求成功
    console.log(first);
}).catch((error) => { // 所有三个 fetch() 全部请求失败
    console.log(error);
});

只要参数实例有一个变成 fulfilled 状态,包装实例就会变成 fulfilled 状态;如果所有参数实例都变成 rejected 状态,包装实例就会变成 rejected 状态。

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

10、Promise.resolve()
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))
11、Promise.reject()
Promise.reject('出错了');
// 等同于
new Promise((resolve, reject) => reject('出错了'))
12、Promise.try()

相关文章

网友评论

      本文标题:ES6 Promise

      本文链接:https://www.haomeiwen.com/subject/elghqdtx.html