- 抽象表达:
- Promise 是一门新的技术(ES6 规范)
- Promise 是 JS 中进行异步编程的新解决方案 备注:旧方案是单纯使用回调函数
- 具体表达:
- 从语法上来说: Promise 是一个构造函数
- 从功能上来说: promise 对象用来封装一个异步操作并可以获取其成功/失败的结果值
指定回调函数的方式更加灵活 1.旧的: 必须在启动异步任务前指定 2. promise: 启动异步任务 => 返回promie对象 => 给promise对象绑定回调函数(甚至可以在异步任务结束后指定/多个)
-
Promise 支持链式调用, 可以解决回调地狱问题 1.什么是回调地狱? : 回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调执行的条件 3.回调地狱的缺点? : 不便于阅读 和 不便于异常处理 3.解决方案? : promise 链式调用 4.终极解决方案 :async/await
-
fs 文件操作
require('fs').readFile('./index.html', (err,data)=>{}) -
AJAX
$.get('/server', (data)=>{}) -
定时器
setTimeout(()=>{}, 2000);
Promise 的状态
实例对象中的一个属性 『PromiseState』
- pending 未决定的
- resolved / fullfilled 成功
- rejected 失败
Promise 对象的值
实例对象中的另一个属性 『PromiseResult』 保存着异步任务『成功/失败』的结果
- resolve
- reject
API
- Promise 构造函数: Promise (exqutor) {} (1) executor 函数:执行 器(resolve, reject) => {} (2) resolve 函数:内部定义成功时我们调用的函数value=> {} (3) reject 函数:内部定义失败时我们调用的函数reason=> {} 说明:executor会在Promise内部立即同步调用,异步操作在执行器中执行
- Promise.prototype.then 方法: (onResolved, onRejected)=> {} (1) onResolved 函数:成功的回调函数(value) => {} (2) onRejected 函数:失败的回调函数(reason) => {} 说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调 返回一个新的promise对象
- Promise.prototype.catch 方法: (onRejected) => {} (1) onRejected 函数:失败的回调函数(reason) => {}
- Promise.resolve 方法: (valμe)=> {} (1) value: 成功的数据或promise对象 说明:返回一个成功/失败的promise对象|
- Promise.reject 方法: (reason) => {} (1) reason: 失败的原因说明:返回一个失败的promise对象
- Promise.all 方法: (promises)=> {} (1) promises: 包含n个promise的数组 说明:返回一个新的promise,只有所有的promise都成功才成功,只要有一一个失败了就直接失败
- Promise.race 方法: (promises)=> {} (1) Promise: 包含n个Promise的数组 说明:返回一个新的Promise,第一个完成的Promise的结果状态就是最终的结果状态
Promise手动封装案例
class Promise {
// 构造方法
constructor(executor) {
// 添加属性
this.PromiseState = 'pending';
this.PromiseResult = null;
this.callbacks = []; // 保存因异步任务而丢弃的数据
// 保存实例对象的 this 的值
const self = this;
// resolve 函数
function resolve(data) {
// console.log(this); // 这里的 this 默认指向的是 window对象
if(self.PromiseState !== 'pending') return;
// 1. 修改对象的状态(PromiseState)
self.PromiseState = 'fulfilled'; // resolve
// 2. 设置对象的结果值 (PromiseResult)
self.PromiseResult = data;
setTimeout(() => {
// 3. 调用成功的回调函数
self.callbacks.forEach(item => {
item.onResolved(data);
});
});
}
// reject 函数
function reject(data) {
if(self.PromiseState !== 'pending') return;
// 1. 修改对象的状态(PromiseState)
self.PromiseState = 'rejected';
// 2. 设置对象的结果值 (PromiseResult)
self.PromiseResult = data;
setTimeout(() => {
// 3. 调用成功的回调函数
self.callbacks.forEach(item => {
item.onRejected(data);
})
});
}
// 捕捉 throw 抛出的 错误 使用 try{}catch(){}
try {
// 同步调用 执行器函数
executor(resolve, reject);
}catch(e) {
// 修改Promise对象的状态为 reject 失败
reject(e);
}
}
// then 方法
then(onResolved, onRejected) {
const self = this;
// 判断回调函数参数
if(typeof onRejected !== 'function') {
onRejected = reason => {
throw reason;
}
}
if(typeof onResolved !== 'function') {
onResolved = value => value
}
return new Promise((resolve, reject) => {
// 封装判断函数
function callback(type) {
try{
// 获取回调函数的执行结果
let result = type(self.PromiseResult);
// 判断
if(result instanceof Promise) {
// 如果是 Promise 类型的对象 通过 then 方法 来进行返回
result.then(v => {
resolve(v);
}, r => {
reject(r);
})
}else {
// 不是 Promise 对象的类型为成功 通过resolve变为Promise对象
resolve(result);
}
}catch(e){
reject(e);
}
}
// 调用回调函数 PromiseState
if(this.PromiseState === 'fulfilled') {
setTimeout(() => {
callback(onResolved);
});
}
if(this.PromiseState === 'rejected') {
setTimeout(() => {
callback(onRejected);
});
}
// 判断 pending 状态 保存 数据
if(this.PromiseState === 'pending') {
this.callbacks.push({
onResolved : function() {
callback(onResolved);
},
onRejected : function() {
callback(onRejected);
}
});
}
});
}
// catch 方法
catch(onRejected) {
return this.then(undefined, onRejected);
}
// resolve 方法
static resolve(value) {
return new Promise((resolve, reject) => {
if(value instanceof Promise) {
value.then(v => {
resolve(v);
}, r => {
reject(r);
});
}else {
resolve(value);
}
});
}
// reject 方法
static reject(reason) {
return new Promise((resolve ,reject) => {
reject(reason);
});
}
// 添加 all 方法
static all(promises) {
// 声明变量 判断成功的promise
let count = 0;
let arr = [];
// 返回promise对象
return new Promise((resolve, reject) => {
for(let i = 0; i < promises.length ; i++) {
promises[i].then(v => {
// 得知成功的promis
count++;
// 将当前Promise对象成功的结果 存入到数组中
arr[i] = v;
if(count === promises.length) {
resolve(arr);
}
},r => {
reject(r);
});
}
});
}
// race 方法
static race(promises) {
return new Promise((resolve ,reject) => {
for(let i = 0; i < promises.length ; i++) {
promises[i].then(v => {
// 修改返回的对象的状态 为成功
resolve(v);
}, r => {
// 修改返回的对象的状态 为失败
reject(r);
});
}
});
}
}
async & await
async
<script>
async function main() {
// 1. 如果返回值是一个非 Promise 类型的数据 表示成功
// return 32;
// 如果返回的是 Promise 对象 结果看它返回的值(类型)
/* return new Promise((resovle, reject) => {
// resovle('OK');
reject("Error");
}); */
// 3. 抛出错误
throw "Error";
}
let result = main();
console.log(result);
</script>
await
<script>
async function main() {
let p = new Promise((resovle,reject) => {
// resovle("OK");
reject("Error");
});
// 1. 右侧为Promise对象的情况
// let res = await p;
// console.log(res);
// 2. 右侧为其它类型的数据
// let res2 = await 20;
// console.log(res2);
// 3. 如果Promise是失败的状态
try {
let res3 = await p;
}catch(e) {
console.log(e);
}
}
main();
</script>
async 和 await 读取文件
const util = require('util');
const fs = require('fs');
const read = util.promisify(fs.readFile);
/* fs.readFile('./1.Promise初体验.html', (err, data1) => {
if(err) throw err;
fs.readFile('./2.Promise-fs模块.js', (err, data2) => {
if(err) throw err;
fs.readFile('./3.Promise实践-AJAX请求.html', (err, data3) => {
if(err) throw err;
console.log(data1 + data2 + data3);
});
});
}); */
// async 和 await
async function main() {
try{
let res1 = await read('./1.Promise初体验.html');
let res2 = await read('./2.Promise-fs模块.js');
let res3 = await read('./3.Promise实践-AJAX请求.html');
console.log(res1 + res2 + res3);
}catch(e){
console.log(e);
}
}
main();
async 和 await 发送AJAX 请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="btn">点击获取段子</button>
<script>
function sendAJAX(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.send();
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response);
}else{
reject(xhr.statusText);
}
}
}
});
}
// 接口地址:" https://api.apiopen.top/getJoke"
let btn = document.querySelector("#btn");
btn.addEventListener("click",async function() {
let duanzi = await sendAJAX("https://api.apiopen.top/getJoke");
console.log(duanzi);
});
</script>
</body>
</html>