ES6 Promise 对象介绍

发布于: 2020 年 07 月 21 日
ES6 Promise 对象介绍

Promise 是一种异步编程的解决方案,代替了以前在异步函数中传入回调函数的写法,解决了深层嵌套引起的回调地狱问题。

首先来简单看一下 Promise 的语法:

new Promise((resolve, reject) => {
// 成功 resolve(value)
// 失败 reject(reason)
});

Promise 作为一个构造函数,使用时需要 new 一个实例,它接收一个函数作为参数,该函数有两个参数 resolvereject

它们均为函数,其中 resolve 函数在异步操作成功时调用,而 reject 是在异步函数操作失败时调用。比如下面这个例子:

const fs = require('fs');
let read = function (path) {
return new Promise((resolve, reject) => {
fs.readFile(path, 'utf8', (err, data) => {
if (err) {
return reject(err);
}
return resolve(data);
});
});
}

我们用 Promise 封装一个 read 函数,读取文件成功或失败时分别调用 resolvereject,成功时传入成功的结果,失败时传入失败的原因。

注意:read 函数在下文中也会用到,不再重复定义

成功后或失败后该如何处理?首先我们来看一下 Promise 的几个状态,一个 Promise 会有三个状态:

  • pending 初始状态,既不成功,也不失败

  • fulfilled 成功

  • rejected 失败

无论最终的状态是成功还是失败,都能够被 then 方法接收,下面来看一下 then 方法。

Promise.then()

then 方法作为 Promise 原型链上的一个方法,可以在实例化后调用,它拥有两个函数类型的参数,分别用于处理成功(onFulfilled)和失败(onRejected)的情况,并且它们只会被调用一个。

例如,我们用前面封装的方法去读取一个文件,如果成功就会打印出 data,如果失败就会打印出 reason。

read('./data1.json').then((data) => {
console.log(data);
}, (reason) => {
console.log(reason);
});

Promise.catch()

catch 方法用于捕获异步操作中 rejected 的情况,例如:

read('../data1.json').then((data) => {
console.log(data);
// dosomething()
}).catch((reason) => {
console.log('catch: ', reason)
});

在这个例子中,如果读取文件失败,则会调用 catch 方法,等同于在 then 里面写上 onRejected 方法:

read('../data1.json').then((data) => {
console.log(data);
// dosomething()
}, (reason) => {
console.log('onRejected: ', reason);
})

当然,catch 方法不仅仅能够捕获 rejected 的情况,如果在 onFulfilled 里抛出异常也是可以被 catch 捕获的。

read('../data1.json').then((data) => {
try {
console.log(data);
} catch (e) {
throw new Error(e);
}
}, (reason) => {
console.log('onRejected: ', reason);
}).catch((reason) => {
console.log('catch: ', reason)
});

在这个例子中,如果 try…catch… 如果抛出错误,也是可以被最后的 catch 方法捕获的,因此我们可以用 catch 方法来代替在 then 里面做 onRejected 的处理。

Promise.all()

Promise.all() 会处理多个 Promise,然后返回一个新的 Promise,一般用于从多个数据源获取数据,最后做统一的处理,例如:

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

p 最终的状态由p1, p2, p3共同决定,只有当都成功时才算成功,p 的状态变更为 fulfilled,然后把所有的结果放在数组里返回,只要有一个失败最终的结果就会失败,p 的状态变更为 rejected,把最先失败的错误信息返回。

一个小例子:

// 都成功才成功, 只有一个失败就失败
const p = Promise.all([
read('../data1.json'),
read('../data2.json'),
]);
p.then((data) => {
console.log(data);
// [ '{"message1": "data1"}', '{"message2": "data2"}' ]
}).catch((err) => {
console.log('catch:', err);
});

Promise.race()

Promise.race()Promise.all() 类似,也是接收一个数组作为参数,处理多个 Promise。

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

但是 p 的状态是由 p1, p2, p3 中状态最先改变的那一个决定的,例如:

const p = Promise.race([
read('../data1.json'),
new Promise((resolve, reject) => {
setTimeout(() => { reject('请求超时!') }, 1000)
})
]);
p.then((data) => {
console.log(data);
}).catch((err) => {
console.log('catch:', err);
});

在这个例子中,如果 read 函数执行完毕,则会返回读取的结果,打印 data,但是如果过了 1000ms read 函数还没有执行完毕,那么就会执行 setTimeout 里的内容,最终会被 catch 捕获。

Promise.resolve()

Promise.resolve() 方法可以把现有的对象(也可能不是对象)转化为 Promise 对象,等价于如下代码:

let p = Promise.resolve('xxx');
// 等价于
let p = new Promise((resolve, reject) => resolve('xxx'));

Promise.resolve() 可以接收一个参数,这个参数分为以下几种情况:

  1. 参数是一个 Promise 对象,Promise.resolve() 会原封不动的返回这个对象。

  2. 参数是一个 thenable 对象,例如:

let obj = {
then: (resolve, reject) => {
resolve('hello');
}
};
let p1 = Promise.resolve(obj);
console.log('p1', p1);
// p1 Promise { <pending> }
p1.then((data) => {
console.log(data);
// hello
});

Promise.resolve 会把这个 thenable 对象转化为 Promise 对象,然后立即调用 thenablethen 方法。

  1. 参数不具有 then 方法,或者不是对象

let p1 = Promise.resolve('hello');
p1.then((data) => {
console.log(data);
// hello
});

传入一个固定值时,返回状态为 resolved,并且会把这个固定值作为 onFulfilled 的参数返回。

Promise.reject()

Promise.reject() 也会返回一个 Promise 对象,并且状态为 rejected,等价于如下代码:

let p1 = Promise.reject('hello');
// 等价于
let p1 = new Promise((resolve, reject) => reject(obj));

Promise.reject() 的参数本身会作为 reject 的理由返回,例如:

let p1 = Promise.reject(read('./data1.json'));
p1.then((data) => {
console.log(data);
}).catch((reason) => {
console.log('catch', reason);
// catch Promise { <pending> }
// 前面 Promise.reject 的参数如果是 'hello',则打印结果为 catch hello
});

此时传入的参数为一个 Promise 对象,最终被 catch 后,打印出的 reason 仍然是一个 Promise 对象。

Ok,以上就是 ES6 Promise 对象的介绍。

总结

  • Promise 对象解决了回调地狱的问题

  • Promise 可以链式调用

  • Promise 结合 async function 用起来会更爽

  • 基于 Promise 的库或 API: Bluebird, [axios](https://github.com/axios/axios), [Fly.js](https://github.com/wendux/fly), [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)

  • Promise A+ 规范参考:https://promisesaplus.com/

Photo by Erik Mclean on Unsplash

发布于: 2020 年 07 月 21 日 阅读数: 6
用户头像

蓝调达里

关注

一个前端工程师 2018.01.01 加入

每天进步一点点ヽ(•̀ω•́ )ゝ,公众号:前端柠檬

评论

发布
暂无评论
ES6 Promise 对象介绍