Promise
Promise 的定义和使用
Promise 是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。
一个 Promise 必然处于以下几种状态之一:
- 待定(
pending):初始状态,既没有被兑现,也没有被拒绝。 - 已兑现(
fulfilled):意味着操作成功完成。 - 已拒绝(
rejected):意味着操作失败。
Promise 的使用:
- Promise 构造函数:
new Promise((resolve, reject)=>{}) Promise.prototype.then方法Promise.prototype.catch方法
一个简单案例:
let p = new Promise(function (resolve, reject) {
// 使用 setTimeout 模拟请求数据库数据操作
setTimeout(function () {
// 这个异步请求数据库数据操作是否正确返回数据
let isRight = true;
if (isRight) {
let data = '数据库中的数据';
// 设置 Promise 对象的状态为操作成功
resolve(data);
} else {
let err = '数据读取失败!'
// 设置 Promise 对象的状态为操作失败
reject(err);
}
}, 1000);
});
p.then(function (value) {
console.log(value);
}, function (reason) {
console.error(reason);
})Copy to clipboardErrorCopied
Promise 封装读取文件
// 使用 nodejs 的 fs 读取文件模块
const fs = require('fs');
const p = new Promise(function (resolve, reject) {
fs.readFile('./resources/为学.txt', (err, data) => {
// err 是一个异常对象
if (err) reject(err);
resolve(data);
})
})
p.then(function (value) {
// 转为字符串输出
console.log(value.toString());
}, function (reason) {
console.log('读取失败!!');
})Copy to clipboardErrorCopied
Promise 封装 Ajax 请求
const p = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('get', 'https://api.apiopen.top/getJoke');
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
// 成功
resolve(xhr.response);
} else {
// 失败
reject(xhr.status);
}
}
}
});
// 指定回调
p.then(function (value) {
console.log(value);
}, function (reason) {
console.error(reason);
})Copy to clipboardErrorCopied
Promise.prototype.then 方法
先复习一下一个 Promise 的三种状态:
- 待定(
pending):初始状态,既没有被兑现,也没有被拒绝。 - 已兑现(
fulfilled):意味着操作成功完成。 - 已拒绝(
rejected):意味着操作失败。
Promise.prototype.then 方法返回的结果依然是 Promise 对象,对象状态由回调函数的执行结果决定。
具体情况如下:
-
若
then方法没有返回值,则then方法返回的对象的状态值为成功fulfilled,返回结果值为undefined。const p = new Promise((resolve, reject) => { setTimeout(() => { // resolve('用户数据') reject('出错了'); }, 1000); }) // 未设定返回值 const res = p.then((value) => { console.log(value); }, (reason) => { console.warn(reason); }) // 打印 then 方法的返回值 console.log(res);Copy to clipboardErrorCopied -
如果回调函数中返回的结果是非
Promise类型的属性,则then方法返回的对象,其状态为成功(fulfilled),返回结果值取决于then方法所执行的是哪个函数(resolve或reject)。const p = new Promise((resolve, reject) => { setTimeout(() => { // resolve('用户数据') reject('出错了'); }, 1000); }) // 返回的非 Promise 对象 const res = p.then((value) => { console.log(value); return '成功了!!'; }, (reason) => { console.warn(reason); return '出错啦!!' }) // 打印 then 方法的返回值 console.log(res);Copy to clipboardErrorCopied -
如果回调函数中返回的结果是
Promise类型(return new Promise()),则then方法返回的Promise对象状态与该返回结果的状态相同,返回值也相同。const p = new Promise((resolve, reject) => { setTimeout(() => { resolve('用户数据') // reject('出错了'); }, 1000); }) const res = p.then((value) => { console.log(value); // 返回 Promise 对象 return new Promise((resolve, reject) => { resolve('(1)成功了!!!'); // reject('(1)出错了!!!') }) }, (reason) => { console.warn(reason); return new Promise((resolve, reject) => { // resolve('(2)成功了!!!'); reject('(2)出错了!!!') }) }) // 打印 then 方法的返回值 console.log(res);Copy to clipboardErrorCopied -
如果回调函数中返回的结果是
throw语句抛出异常,则then方法的对象的状态值为rejected,返回结果值为throw抛出的字面量或者Error对象。const p = new Promise((resolve, reject) => { setTimeout(() => { resolve('用户数据'); }, 1000); }); const res = p.then((value) => { console.log(value); return new Promise((resolve, reject) => { throw new Error('错误了!!'); }) }); // 打印结果 console.log(res);Copy to clipboardErrorCopied
链式调用
Promise.prototype.then 方法返回的结果还是 Promise 对象,这意味着我们可以继续在该结果上使用 then 方法,也就是链式调用。
const p = new Promise(resolve=>{}, reject=>{});
p.then(value=>{}, reason=>{})
.then(value=>{}, reason=>{})
.then(value=>{}, reason=>{})
...Copy to clipboardErrorCopied
链式调用练习-多个文件读取
const fs = require('fs');
let p = new Promise((resolve, reject) => {
fs.readFile('./resources/users.md', (err, data) => {
// 传给下一轮文件读取操作
resolve(data);
})
});
p.then(value => {
return new Promise((resolve, reject) => {
// value 为第一次读取的文件数据,data 为第二次(当前)读取的数据
fs.readFile('./resources/orders.md', (err, data) => {
// 将上轮读取结果和本轮合并传到下一轮轮读取操作
resolve([value, data]);
});
});
}).then(value => {
return new Promise((resolve, reject) => {
fs.readFile('./resources/goods.md', (err, data) => {
// value 为上一轮传递过来的文件数据数组
value.push(data);
// 传给下一轮操作
resolve(value);
});
});
}).then(value => {
// 合并数组元素,输出
console.log(value.join('\n'));
});Copy to clipboardErrorCopied
Promise.prototype.catch
catch() 方法返回一个 Promise,并且处理拒绝的情况。它的行为与调用 Promise.prototype.then(undefined, onRejected) 相同。
即:
obj.catch(onRejected);Copy to clipboardErrorCopied
等同于:
obj.then(undefined, onRejected);Copy to clipboardErrorCopied
语法:
p.catch(onRejected);
p.catch(function(reason) {
// 拒绝
});Copy to clipboardErrorCopied
举例:
var p1 = new Promise(function (resolve, reject) {
resolve('Success');
});
p1.then(function (value) {
console.log(value); // "Success!"
throw 'oh, no!';
}).catch(function (e) {
console.log(e); // "oh, no!"
}).then(function () {
console.log('有 catch 捕获异常,所以这句输出');
}, function () {
console.log('没有 catch 捕获异常,这句将不会输出');
});Copy to clipboardErrorCopied
输出结果:
Success
oh, no!
有 catch 捕获异常,所以这句输出Copy to clipboardErrorCopied
以上只是 Promise 的入门,更多还要进一步深入学习。