❤Promise(then,catch,finally,all,race,allsettled,any)-三千字总结
❤️ ❤Promise(then,catch,finally,all,race,allsettled,any)-三千字总结
1、Promise简介
基本使用先看一眼
new Promise(( resolve, reject ) =>{})
(1)认识
含义
先看看这个Promise
单词的含义:翻译成中文是许诺
,非常好的名字,我们看看具体用来做什么
诞生目的
promise是为了解决 JavaScript 异步编程中的问题,旧的的ajax发单个请求还好,如果多请求不断嵌套和复用,将十分混乱,promise主要是为了解决这种情景而出现的,他提供了一种更优雅和可靠的方式来处理异步操作。
实用场景
举个例子(现在我们需要通过一个接口请求id ,再根据id请求用户名.再根据用户名,再根据用户名获取手机号),这个时候就用到这个promise
(2)发展历程
Promise
最早由社区提出,并被添加到 ECMAScript 6(ES6)标准中,
随着时间推移,Promise
在后续的 ECMAScript 标准中也增加了更多与 Promise
相关的特性,async/await
等,进一步简化了异步代码的编写。
(3)特点
- 状态管理:三种状态,【pending(等待)、fulfilled(已成功)、rejected(已失败)】 ,可以清晰地知道异步操作的状态并进行后续操作。
- 链式调用:可以轻松地串联多个异步操作,避免回调地狱问题。
- 错误处理:提供了统一的错误处理机制,通过
catch
方法可以捕获链中任意位置抛出的错误。
(4)优点
让传统的多ajax请求更优雅
(5)缺点
-
许诺,意思就是一旦许诺完毕,就无法更改! 所以,一个Promise一旦新建它就会立即执行,无法中途取消。
-
如果不设置回调函数,Promise内部抛出的错误,不会反应到外部,我们也压根得不到,不知道发生了什么。
-当处于Pending状态时,无法得知目前狀態(不知道是刚刚开始还是即将完成)。
如果某些事件不断地反复发生,一般来说,使用 Stream 模式是比部署Promise更好的选择。
(6)Promise
构造函数
首先你得清楚,他就是函数,那他是用来做什么的呢。
来创建 Promise
对象的函数。通过调用 new Promise(executor)
来创建一个新的 Promise
实例,其中 executor
是一个带有 resolve
和 reject
两个参数的函数:
const myPromise = new Promise((resolve, reject) => {
// 异步操作代码
if (/* 操作成功 */) {
resolve('成功的结果');
} else {
reject('失败的原因');
}
});
如图所示,其实这个就是传入的那个函数executor
也就是在 Promise 构造函数中,接受一个执行器函数,该函数立即执行,并包含异步操作的逻辑,通过 resolve
或 reject
来改变 Promise
的状态。
(7)Promise 实例
通过 Promise
构造函数创建的对象,代表一个异步操作的最终结果(成功或失败)
可以调用 .then()
、.catch()
和 .finally()
方法来处理异步操作的结果。
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('操作成功'); // 模拟异步操作成功
}, 1000);
});
myPromise.then(result => {
console.log(result); // 输出 "操作成功"
}).catch(error => {
console.error(error);
});
(8)解决痛点
这里我们可以简单看一下没有promise的时候是怎么使用的
我们先以一个简单的网络请求为示例:
// 请求A 函数
(function A(resultA){
// 处理resultA
...
resultA;
})
两个或者多个呢
// 请求A 函数
(function A(resultA){
// 处理resultA
...
function B(resultB){
// 处理 resultB
...
function C(resultC){
// 处理 resultC
...
}
}
})
来看看六层结构的时候是什么样子
// 六层嵌套结构
// 请求A 函数
(function A(resultA){
console.log('处理 resultA:', resultA); // 处理resultA
function B(resultB){
console.log('处理 resultB:', resultB);// 处理 resultB
function C(resultC){
console.log('处理 resultC:', resultC); // 处理 resultC
function D(resultD){
console.log('处理 resultD:', resultD); // 处理 resultD
function E(resultE){
console.log('处理 resultE:', resultE); // 处理 resultE
function F(resultF){
console.log('处理 resultF:', resultF); // 处理 resultF
}
// 调用函数F
const resultF = '结果F';
F(resultF);
}
const resultE = '结果E'; // 调用函数E
E(resultE);
}
const resultD = '结果D'; // 调用函数D
D(resultD);
}
const resultC = '结果C'; // 调用函数C
C(resultC);
}
const resultB = '结果B'; // 调用函数B
B(resultB);
})('结果A');
难以维护,有时候我们还要在里面添加更多的逻辑和操作
但是我们使用更加友好的代码组织方式,把异步写成同步的方式是不是更好一些呢?
// 调用函数A并获取结果
let resultA = A();
// 调用函数B并获取结果,传入resultA
let resultB = B(resultA);
// 调用函数C并获取结果,传入resultB
let resultC = C(resultB);
// 调用函数D并获取结果,传入resultC
let resultD = D(resultC);
// 调用函数E并获取结果,传入resultD
let resultE = E(resultD);
// 调用函数F,传入resultE
F(resultE);
应用到正式的写法之中就可以缩减为
// Define request functions (assuming they return Promises)
function request1() {
return new Promise((resolve, reject) => {
// Async operation, simulate request 1
setTimeout(() => {
console.log('Request 1 completed');
resolve('Result 1'); // Simulate successful request 1 with result 1
}, 1000);
});
}
function request2(result1) {
return new Promise((resolve, reject) => {
// Async operation, simulate request 2 using result 1
setTimeout(() => {
console.log('Request 2 completed, using:', result1);
resolve('Result 2'); // Simulate successful request 2 with result 2
}, 1000);
});
}
function request3(result2) {
return new Promise((resolve, reject) => {
// Async operation, simulate request 3 using result 2
setTimeout(() => {
console.log('Request 3 completed, using:', result2);
resolve('Result 3'); // Simulate successful request 3 with result 3
}, 1000);
});
}
function request4(result3) {
return new Promise((resolve, reject) => {
// Async operation, simulate request 4 using result 3
setTimeout(() => {
console.log('Request 4 completed, using:', result3);
resolve('Result 4'); // Simulate successful request 4 with result 4
}, 1000);
});
}
function request5(result4) {
return new Promise((resolve, reject) => {
// Async operation, simulate request 5 using result 4
setTimeout(() => {
console.log('Request 5 completed, using:', result4);
resolve('Result 5'); // Simulate successful request 5 with result 5
}, 1000);
});
}
// Define function to handle exceptions
function handleException(error) {
console.error('Exception occurred:', error);
}
// Using Promise chaining
new Promise(request1)
.then(result1 => request2(result1))
.then(result2 => request3(result2))
.then(result3 => request4(result3))
.then(result4 => request5(result4))
.then(result5 => {
console.log('All requests completed, final result:', result5);
})
.catch(error => handleException(error));
这个时候就诞生了最著名的 Q 和 bluebird等库。
2、Promise状态
一个 Promise
对象有三种状态:
- Pending(等待):初始状态,既不成功,也不失败。
- Fulfilled(已成功 又称为Resolved):操作成功
- Rejected(已失败):操作失败
写一个普通的Promise来看一下我们对应的状态
首先是成功和完成!
const myPromise = new Promise((resolve, reject) => {
const success = true; // 模拟异步操作的结果
if (success) {
resolve('myPromise 操作成功!'); // 操作成功时调用 resolve
} else {
reject('myPromise 操作失败!'); // 操作失败时调用 reject
}
});
myPromise
.then(value => {
console.log(value); // 操作成功时执行
})
.catch(error => {
console.error(error); // 操作失败时执行
})
.finally(() => {
console.log('myPromise has completed.'); // 无论成功或失败都会执行
});
操作成功以后返回给我们!
操作失败:(把success换成false)
3、promise.实例对象方法
先看一下我们使用上述的方法
myPromise
.then(value => {
console.log(value); // 操作成功时执行
})
.catch(error => {
console.error(error); // 操作失败时执行
})
.finally(() => {
console.log('Operation has completed.'); // 无论成功或失败都会执行
});
(1) .then
用户 Promise
成功时要执行的回调函数。它还可以接受一个可选的第二个参数,用于处理 Promise
被拒绝的情况
就类似我们登录请求不成功会给用户提示或者去登录页登录一样
myPromise.then(onFulfilled, onRejected);
onFulfilled
:当Promise
成功时要执行的回调函数。onRejected
:当Promise
被拒绝时要执行的回调函数(可选)
(2) .catch
catch
方法用于定义当 Promise
被拒绝时要执行的回调函数。它相当于 then
方法的第二个参数。
通常我们会在这里区捕获一些接口异常信息等!
myPromise.catch(onRejected);
(3) .finally
ES9(2018)新实例方法
finally
在 Promise
结束时(无论成功还是失败)执行,也就是最后肯定会执行这个,有时候我们就会拿来查询之前改的列表状态
myPromise.finally(onFinally);
4、Promise静态方法
(1) Promise.resolve
(静态方法)
Promise.resolve
方法返回一个以给定值解析后的 Promise
。
如果该值是一个 Promise
,那么直接返回这个 Promise
const resolvedPromise = Promise.resolve(42);
resolvedPromise.then(value => {
console.log(value); // 42
});
(2) Promise.reject
方法(静态方法)
Promise.reject
返回一个状态为 rejected 的 Promise
对象,并且可以指定拒绝的原因(通常是一个错误对象)。
我们可以在异步操作时候立马拒绝 Promise
时候使用,比如(某些条件不满足或者发生错误时)
const rejectedPromise = Promise.reject(new Error('Something went wrong'));
rejectedPromise.catch(error => {
console.error(error); // Error: Something went wrong
});
(3) Promise.all
接受一个 Promise
的迭代器,并返回一个新的 Promise
,该 Promise
在所有传入的 Promise
都完成时完成,并带有一个数组的成功结果。
如果任意一个传入的 Promise
失败,那么返回的 Promise
将立即失败,并带有第一个失败的 Promise
的错误原因。
举个例子,必须查询出三种类别(由三个接口提供),再依靠我们查出来的类别进行选择时我们可以采用。
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(resolve, 100, 'foo'));
const promise3 = 42;
Promise.all([promise1, promise2, promise3]).then(values => {
console.log(values); // [3, "foo", 42]
});
当我们把其中定时器加上三秒的时候,也是之后给我们一起返回
(4)Promise.race
翻译成中文就是竞争竞赛
,就是有个人赢了那就是结束了
接受一个 Promise
的迭代器,并返回一个新的 Promise
,该 Promise
在传入的任意一个 Promise
完成时立即完成,带有这个 Promise
的成功结果或错误原因。
就是类似于 或 的关系,A||B 有任意一个成立就可以!
const promise1 = new Promise((resolve, reject) => setTimeout(resolve, 5000, 'one'));
const promise2 = new Promise((resolve, reject) => setTimeout(resolve, 10000, 'two'));
Promise.race([promise1, promise2]).then(value => {
console.log(value); // "two"
});
5、promise 对象实例和Promise静态方法区分
这里可能对于promise上的对象实例和静态方法不清楚,我们,我们看一下两者之间的区别
以Promise.reject
和promise.then
来区分
不同点
- 调用方式:
Promise.reject
是一个静态方法,直接通过Promise
构造函数调用,不需要先创建Promise
实例。promise.then
是Promise
实例的方法,必须在已有Promise
实例上调用。
- 作用:
Promise.reject
用于创建一个立即被拒绝的Promise
对象,通常用于快速返回失败状态的场景。promise.then
用于设置成功和失败时的回调函数,允许进行链式操作。
相同点
- 都可以用来处理
Promise
的状态变化异步操作的结果。 - 都支持链式调用,可连续地对异步操作进行处理。
这里我们简单写一下使用区分一下:
// 1 使用 Promise.reject
const rejectedPromise = Promise.reject(new Error('Reason for rejection'));
rejectedPromise.catch(error => {
console.error(error.message); // Output: "Reason for rejection"
});
// 2 使用 promise.then
const myPromise = new Promise((resolve, reject) => {
const success = false; // 模拟一个失败的异步操作
if (success) {
resolve('Operation was successful!');
} else {
reject(new Error('Operation failed!'));
}
});
myPromise.then(
result => {
console.log(result); // 操作成功时执行
},
error => {
console.error(error.message); // 操作失败时执行
}
);
6、Promise链式调用
链式调用可以轻松处理一系列的异步操作并优化和简化我们的代码
new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000); // 1秒后变为resolved状态
})
.then(result => {
console.log(result); // 1
return result * 2;
})
.then(result => {
console.log(result); // 2
return result * 2;
})
.then(result => {
console.log(result); // 4
return result * 2;
});
打印出可以看到
(1) 链式错误
在 Promise
链中,如果某个 then
或者 catch
抛出了错误,后续的 catch
将会捕获到这个错误
我们在链式之中抛出一个异常试试
new Promise((resolve, reject) => {
throw new Error("Whoops!");
})
.catch(error => {
console.error(error); // Error: Whoops!
return "Recovered";
})
.then(result => {
console.log(result); // Recovered
});
7、手写一个 Promise过程
转载自:https://juejin.cn/post/7382868373882880000