目录
前言
Promise是什么
Promise概述
Promise 是异步编程的一种解决方案,它是ES6 规范的一门新的技术。
- 从语法上讲,promise是一个对象、也是一个构造函数,从它可以获取异步操作的消息。
- 从本意上讲,它也是承诺,承诺会给你一个结果。
- 从功能上来说: promise 对象用来封装一个异步操作并可以获取其成功/ 失败的结果值。
Promise的状态
promise实例有三种状态:
- 异步操作未完成(
pending
) - 异步操作成功(
resolved
/fulfilled
) - 异步操作失败(
rejected
)
promise 的状态改变:
pending
变为resolved
/fulfilled
pending
变为rejected
状态只能改变一次,一旦改变,就不会再变,且都会有一个结果数据,成功的结果数据一般称为 value, 失败的结果数据一般称为 reason
promise的基本流程
代码展示如下,我们只调取了成功的回调,可以得到最后的结果为 ‘okk’
const p = new Promise((resolve, reject) => {
// 异步语句 延时器
setTimeout(() => {
if ('异步操作成功') {
// 成功状态
resolve('okk');
} else {
// 失败状态
reject('err');
}
},1000);
});
// 调用 then 方法 指定回调
p.then(value => {
// 成功回调
console.log(value);
}, reason => {
// 失败回调
console.log(reason);
});
这里也要说一下改变 promise 状态和指定回调函数执行顺序,后续博客会系统的更新该部分问题,这里我们只需要知道只有当状态改变后才能得到数据,也就是说,当前状态由
pending
变为resolved
/fulfilled
后,才能得到成功的回调数据 ‘okk’ 。
为什么要用Promise
1. 指定回调函数的方式更加灵活
旧的: 必须在启动异步任务前指定
promise : 启动异步任务 => 返回promie对象 => 给promise对象绑定回调函数(甚至可以在异步任务结束后指定/多个)
2. 支持链式调用, 可以解决回调地狱问题
2.1 什么是回调地狱
回调地狱是指:多层嵌套函数,函数的返回值是下一个函数的执行条件。
setTimeout(() => {
console.log('1');
setTimeout(() => {
console.log('2');
setTimeout(() => {
console.log('3');
}, 1000);
}, 2000);
}, 3000);
回调函数中嵌套回调函数的情况就叫做回调地狱,可以看到,上面嵌套了三层延时器(也是一种回调函数),最后每隔一秒一次输出‘1’,‘2’,‘3’
回调地狱的缺点是不便于阅读 不便于异常处理
2.2 原生Promise链式解决方案
const test = n => {
return new Promise((resolve, reject) => {
// 异步任务
setTimeout(() => {
resolve(n);
}, 1000);
});
}
test(1).then(data => {
console.log(data);
return test(2);
}).then(data => {
console.log(data);
return test(3);
}).then(data => {
console.log(data);
}).catch(data => {
console.log(data);
});
2.3 Promise的async/await解决(终极方案)
const test1 = n => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(n)
}, 1000);
});
}
const test = async () => {
console.log(await test1(1));
console.log(await test1(2));
console.log(await test1(3));
}
test();
Promise 的几个常用小案例
Promise 封装 fs 读取文件操作
/**
* 封装一个函数 mineReadFile 读取文件内容
* 参数: path 文件路径
* 返回: promise 对象
*/
let mineReadFile = (path) => {
return new Promise ((resolve, reject) => {
//读取文件
require('fs').readFile(path, (err, data) => {
// 判断
if (err) reject(err);
// 成功
resolve(data);
});
});
}
mineReadFile('./resource/content.txt').then(value => {
// 输出文件内容(成功)
console.log(value.toString());
}, reason => {
console.log(reason);
});
Promise 的 util.promisify 方法
可以将函数直接变成promise的封装方式,不用再去手动封装
//引入 util 模块
const util = require('util');
//引入 fs 模块
const fs = require('fs');
//返回一个新的函数
let mineReadFile = util.promisify(fs.readFile);
mineReadFile('./resource/content.txt').then(value=>{
console.log(value.toString());
}, reason=> {
console.log(reason);
});
Promise 封装 Ajax 异步请求
/**
* 封装一个函数 sendAJAX 发送 GET AJAX 请求
* 参数 URL
* 返回结果 Promise 对象
*/
const sendAJAX = (url) => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.open('GET', url);
xhr.send();
// 处理结果
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
// 判断成功
if(xhr.status >= 200 && xhr.status < 300) {
// 成功的结果为响应体
resolve(xhr.response);
} else {
reject(xhr.status);
}
}
}
});
}
sendAJAX('https://pagead2.googlesyndication.com/getconfig/sodar?sv=200&tid=gda&tv=r20220718&st=env').then(value => {
console.log(value);
}, reason => {
console.log(reason);
})
本文中使用到的一些Promise的API(如 then, catch等方法)见下一篇博客
Promise学习(二)一篇文章带你快速了解Promise中的常用API
Authors: min
时间: 2022年7月24日