1. Promise数组的串行执行

例如,如果你有一组接口需要串行执行,你可能首先想到使用await

const requestAry = [() => api.request1(), () => api.request2(), () => api.request3()];
for (const requestItem of requestAry) {
  await requestItem();
}

如果使用promise,可以使用then函数串联多个promise,实现串行执行。

const requestAry = [() => api.request1(), () => api.request2(), () => api.request3()];
const finallyPromise = requestAry.reduce(
     (currentPromise, nextRequest) => currentPromise.then(() => nextRequest()),
     Promise.resolve() // Create an initial promise for linking promises in the array
);

2. 在新的 Promise 范围之外更改状态

假设你有多个页面,其功能要求在允许使用之前收集用户信息。 点击使用某个功能之前,会弹出一个弹框进行信息收集。 你会如何实施这个?

以下是不同级别前端同学的实现思路:

初级前端:我写一个模态框,然后复制粘贴到其他页面。 效率非常高!

中级前端:这个不好维护。 我们需要单独封装这个组件,并在需要的页面引入!

高级前端:安装任何密封的东西!!!把方法调用写在所有页面都可以调用的地方不是更好吗?

想要了解高级前端是如何实现的,以vue3为例,看一下下面的例子。

<!-- App.vue -->
<template>
<!-- The following is the modal box component -->
   <div class="modal" v-show="visible">
     <div>
       User name: <input v-model="info.name" />
     </div>
     <!-- Other information -->
     <button @click="handleCancel">Cancel</button>
     <button @click="handleConfirm">Submit</button>
   </div>
   <!-- Page components -->
</template>
<script setup>
import { provide } from 'vue';
const visible = ref(false);
const info = reactive({
   name: ''
});
let resolveFn, rejectFn;
// Pass the information collection function to the following
provide('getInfoByModal', () => {
   visible.value = true;
   return new Promise((resolve, reject) => {
     // Assign the two functions to the outside and break through the promise scope
     resolveFn = resolve;
     rejectFn = reject;
   });
})
const handleConfirm = () => {
   resolveFn && resolveFn(info);
};
const handleCancel = () => {
   rejectFn && rejectFn(new Error('User has canceled'));
};
</script>

接下来,getInfoByModal就可以通过直接调用模态框来轻松获取用户填写的数据。

<template>
   <button @click="handleClick">Fill in the information</button>
</template>

<script setup>
import { inject } from 'vue';
const getInfoByModal = inject('getInfoByModal');
const handleClick = async () => {
   // After the call, the modal box will be displayed. After the user clicks to confirm, the promise will be changed to the fullfilled state to obtain the user information.
   const info = await getInfoByModal();
   await api.submitInfo(info);
}
</script>

这也是很多UI组件库中封装常用组件的一种方式。


3.彻底明确then/catch/finally返回值

一句话概括就是,上面三个函数都会返回一个新的promise包装对象。包装后的值是执行回调函数的返回值。

如果回调函数抛出错误,它将包装拒绝状态承诺。 似乎不太容易理解,我们来看一个例子:

我们可以将它们一一复制到浏览器控制台并运行它们以帮助理解。

// then function
Promise.resolve().then(() => 1); // The return value is new Promise(resolve => resolve(1))
Promise.resolve().then(() => Promise.resolve(2)); // Return new Promise(resolve => resolve(Promise.resolve(2)))
Promise.resolve().then(() => {
   throw new Error('abc')
}); // Return new Promise(resolve => resolve(Promise.reject(new Error('abc'))))
Promise.reject().then(() => 1, () => 2); // The return value is new Promise(resolve => resolve(2))

//catch function
Promise.reject().catch(() => 3); // The return value is new Promise(resolve => resolve(3))
Promise.resolve().catch(() => 4); // The return value is new Promise(resolve => resolve(promise object that calls catch))
//When the finally function returns a non-promise value, return the promise object before the finally function.
Promise.resolve().finally(() => {}); // Return Promise.resolve()
Promise.reject().finally(() => {}); // Return Promise.reject()
// When the return value of the finally function is promise, wait for the returned promise to be parsed before returning the promise object before the finally function.
Promise.resolve(5).finally(() => new Promise(res => {
   setTimeout(res, 1000);
})); // Return the Promise in pending status, which will be resolved to 5 after 1 second.
Promise.reject(6).finally(() => new Promise(res => {
   setTimeout(res, 1000);
})); // Return the Promise in the pending state, and throw the number 6 after 1 second

4.then函数的第二次回调和catch回调有什么区别?

当请求发生错误时,会触发 Promisethen 的第二个回调函数和 catch。 乍一看没有区别,但实际上前者无法捕获then当前第一个回调函数中抛出的错误,但catch可以。

Promise.resolve().then(
   () => {
     throw new Error('Error from success callback');
   },
   () => {
     // will not be executed
   }
).catch(reason => {
   console.log(reason.message); // Will print out "error from success callback"
});

小结

熟练掌握Promise能更高效地解决异步任务依赖、并发控制等问题,提升代码的可读性和健壮性。

无论是在处理复杂的异步逻辑,还是优化资源利用率方面都会使用到。

想成为前端大牛吗?快点学起来吧!