【Javascript】Promise形象比喻
我们可以把 Promise 形象地比喻为一个“外卖订单”,它有三种状态:下单中、已送达、已取消。这个比喻可以帮助你理解 Promise 的工作机制。
比喻解释
Pending(下单中):
当你在外卖平台上创建一个订单时,订单状态是“下单中”。此时,外卖还没有送达,也没有取消,你在等待外卖的处理结果。
对应于 Promise,刚创建时的状态就是 Pending
。
Fulfilled(已送达):
当外卖小哥把你的餐送到并交给你时,订单状态变为“已送达”。你得到了你期望的结果,可以开始享用美食。
对应于 Promise,被 resolve
时的状态是 Fulfilled
,这时你可以在 .then
方法中处理结果。
Rejected(已取消):
如果外卖因为某些原因(例如餐厅关闭或配送问题)被取消了,订单状态变为“已取消”。你没有得到你期望的餐,并可能需要处理退款或其他问题。
对应于 Promise,被 reject
时的状态是 Rejected
,这时你可以在 .catch
方法中处理错误。
示例解释
// 创建一个外卖订单(Promise)
const orderFood = new Promise((resolve, reject) => {// 模拟外卖处理过程setTimeout(() => {const isDelivered = Math.random() > 0.5; // 50% 概率送达,50% 概率取消if (isDelivered) {resolve('外卖已送达'); // 订单成功} else {reject('外卖已取消'); // 订单失败}}, 2000); // 模拟 2 秒的送餐时间
});// 处理订单结果
orderFood.then(message => {console.log(message); // 外卖已送达}).catch(error => {console.error(error); // 外卖已取消});
在这个示例中:
当你创建 orderFood 这个 Promise 对象时,订单状态是“下单中”(Pending
)。
经过 2 秒的模拟送餐时间,订单状态会变成“已送达”(Fulfilled)或者“已取消”(Rejected
),并分别调用相应的回调函数处理结果。
链式调用的比喻
你可以想象链式调用 .then 和 .catch 像是处理外卖订单过程中的一系列步骤。例如,确认送达后可以继续处理支付和评价步骤:
orderFood.then(message => {console.log(message); // 外卖已送达return '确认支付';}).then(paymentMessage => {console.log(paymentMessage); // 确认支付return '给好评';}).then(reviewMessage => {console.log(reviewMessage); // 给好评}).catch(error => {console.error('处理失败:', error); // 处理失败,例如外卖已取消});
在这个扩展的比喻中,每个 .then
都是订单流程中的一个步骤,只有前一步成功完成,下一步才会继续进行。如果某一步失败(例如外卖被取消),错误处理(.catch
)就会被触发,处理相应的错误情况。
项目中的运用
其实是最近在写一个后台管理项目,我喜欢用.then
和.catch
<script setup lang="ts">
import { User, Lock } from "@element-plus/icons-vue";
import { reactive, ref } from "vue";
import { useRouter } from 'vue-router'
import { ElNotification } from "element-plus";
//引入用户相关的小仓库
import useUserStore from "@/store/modules/user";
let useStore = useUserStore()//定义变量控制按钮加载效果
let loading = ref(false)
//获取路由器
let $router = useRouter()
//收集账号与密码的数据
let loginForm = reactive({ username: '', password: '' })//登录按钮回调
const login = () => {//按钮加载效果loading.value = true//通知仓库发登录请求//请求成功->首页展示数据的地方//请求失败->弹出登录失败的信息useStore.useLogin(loginForm).then(() => {//编程式跳转到数据首页$router.push('/')//登录成功提示信息ElNotification({type: 'success',message: '登录成功'})//登录成功加载效果消失loading.value = false}).catch((error) => {//登录失败加载效果消失loading.value = falseElNotification({type: 'error', message: error.message})})
}
</script>
当然,用try...catch
可能是一个更好的选择
// 登录按钮回调
const login = async () => {// 按钮加载效果loading.value = true;try {// 通知仓库发登录请求await useStore.useLogin(loginForm);// 编程式跳转到数据首页$router.push('/');// 登录成功提示信息ElNotification({type: 'success',message: '登录成功'});} catch (err) {// 使用类型断言确保 err 是 Error 类型const error = err as Error;// 登录失败提示信息ElNotification({type: 'error',message: error.message || '登录失败'});} finally {// 登录成功或失败加载效果消失loading.value = false;}
};