ES6 Promise 对象介绍

用户头像
Verlime
关注
发布于: 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 日 阅读数: 28
用户头像

Verlime

关注

一个前端工程师 2018.01.01 加入

每天进步一点点ヽ(•̀ω•́ )ゝ

评论

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