❤️ 谢谢支持
喜欢的话别忘了 关注、点赞哦~。
如果使用promise的写法,那么你可以使用then函数来串联多个promise,从而实现串行执行。
const requestAry = [() => api.request1(), () => api.request2(), () => api.request3()]; const finallyPromise = requestAry.reduce( (currentPromise, nextRequest) => currentPromise.then(() => nextRequest()), Promise.resolve(); // 创建一个初始promise,用于链接数组内的promise );
### 2. 在new Promise作用域外更改状态
假设你有多个页面的一些功能需要先收集用户的信息才能允许使用,在点击使用某功能前先弹出信息收集的弹框,你会怎么实现呢?
以下是不同水平的前端同学的实现思路:
**初级前端**:我写一个模态框,然后复制粘贴到其他页面,效率很杠杠的!
**中级前端**:你这不便于维护,我们要单独封装一下这个组件,在需要的页面引入使用!
**高级前端**:封什么装什么封!!!写在所有页面都能调用的地方,一个方法调用岂不更好?
看看高级前端怎么实现的,以vue3为例来看看下面的示例。
接下来直接调用`getInfoByModal`即可使用模态框,轻松获取用户填写的数据。
这也是很多UI组件库中对常用组件的一种封装方式。
### 3. async/await的另类用法
很多人只知道在`async函数`调用时用`await`接收返回值,但不知道`async函数`其实就是一个返回promise的函数,例如下面两个函数是等价的:
const fn1 = async () => 1; const fn2 = () => Promise.resolve(1);
fn1(); // 也返回一个值为1的promise对象
而`await`在大部分情况下在后面接promise对象,并等待它成为fullfilled状态,因此下面的fn1函数等待也是等价的:
await fn1();
const promiseInst = fn1(); await promiseInst;
**然而,await还有一个鲜为人知的秘密**,当后面跟的是非promise对象的值时,它会将这个值使用promise对象包装,因此await后的代码一定是异步执行的。如下示例:
Promise.resolve().then(() => { console.log(1); }); await 2; console.log(2); // 打印顺序位:1 2
等价于
Promise.resolve().then(() => { console.log(1); }); Promise.resolve().then(() => { console.log(2); });
### 4. promise实现请求共享
当一个请求已发出但还未响应时,又发起了相同请求,就会造成了请求浪费,此时我们就可以将第一个请求的响应共享给第二个请求。
request('GET', '/test-api').then(response1 => { // ... }); request('GET', '/test-api').then(response2 => { // ... });
上面两个请求其实只会真正发出一次,并且同时收到相同的响应值。
那么,请求共享会有哪几个使用场景呢?我认为有以下三个:
1. 当一个页面同时渲染多个内部自获取数据的组件时;
2. 提交按钮未被禁用,用户连续点击了多次提交按钮;
3. 在预加载数据的情况下,还未完成预加载就进入了预加载页面;
这也是alova的高级功能之一,实现请求共享需要用到promise的缓存功能,即一个promise对象可以通过多次await获取到数据,简单的实现思路如下:
const pendingPromises = {}; function request(type, url, data) { // 使用请求信息作为唯一的请求key,缓存正在请求的promise对象 // 相同key的请求将复用promise const requestKey = JSON.stringify([type, url, data]); if (pendingPromises[requestKey]) { return pendingPromises[requestKey]; } const fetchPromise = fetch(url, { method: type, data: JSON.stringify(data) }) .then(response => response.json()) .finally(() => { delete pendingPromises[requestKey]; }); return pendingPromises[requestKey] = fetchPromise; }
### 5. 同时调用resolve和reject会怎么样?
大家都知道promise分别有`pending/fullfilled/rejected`三种状态,但例如下面的示例中,promise最终是什么状态?
const promise = new Promise((resolve, reject) => { resolve(); reject(); });
正确答案是`fullfilled`状态,我们只需要记住,promise一旦从`pending`状态转到另一种状态,就不可再更改了,因此示例中先被转到了`fullfilled`状态,再调用`reject()`也就不会再更改为`rejected`状态了。
### 6. 彻底理清then/catch/finally返回值
先总结成一句话,就是**以上三个函数都会返回一个新的promise包装对象,被包装的值为被执行的回调函数的返回值,回调函数抛出错误则会包装一个rejected状态的promise。**,好像不是很好理解,我们来看看例子:
// then函数 Promise.resolve().then(() => 1); // 返回值为 new Promise(resolve => resolve(1)) Promise.resolve().then(() => Promise.resolve(2)); // 返回 new Promise(resolve => resolve(Promise.resolve(2))) Promise.resolve().then(() => { throw new Error('abc') }); // 返回 new Promise(resolve => resolve(Promise.reject(new Error('abc')))) Promise.reject().then(() => 1, () = 2); // 返回值为 new Promise(resolve => resolve(2))
// catch函数 Promise.reject().catch(() => 3); // 返回值为 new Promise(resolve => resolve(3)) Promise.resolve().catch(() => 4); // 返回值为 new Promise(resolve => resolve(调用catch的promise对象))
// finally函数 // 以下返回值均为 new Promise(resolve => resolve(调用finally的promise对象)) Promise.resolve().finally(() => {}); Promise.reject().finally(() => {});
### 7. then函数的第二个回调和catch回调有什么不同?
promise的then的第二个回调函数和catch在请求出错时都会被触发,咋一看没什么区别啊,但其实,前者不能捕获当前then第一个回调函数中抛出的错误,但catch可以。
Promise.resolve().then( () => { throw new Error('来自成功回调的错误'); }, () => { // 不会被执行 } ).catch(reason => { console.log(reason.message); // 将打印出"来自成功回调的错误" });
其原理也正如于上一点所言,catch函数是在then函数返回的rejected状态的promise上调用的,自然也就可以捕获到它的错误。
### 8. (压轴)promise实现koa2洋葱中间件模型
koa2框架引入了洋葱模型,可以让你的请求像剥洋葱一样,一层层进入再反向一层层出来,从而实现对请求统一的前后置处理。

我们来看一个简单的koa2洋葱模型:
const app = new Koa(); app.use(async (ctx, next) => { console.log('a-start'); await next(); console.log('a-end'); }); app.use(async (ctx, next) => { console.log('b-start'); await next(); console.log('b-end'); });
app.listen(3000);
以上的输出为 `a-start -> b-start -> b-end -> a-end`,这么神奇的输出顺序是如何做到的呢,某人不才,使用了20行左右的代码简单实现了一番,如有与koa雷同,纯属巧合。
接下来我们分析一番
>
### 总结
**前端资料汇总**
**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://docs.qq.com/doc/DSmRnRGxvUkxTREhO)**

* 框架原理真的深入某一部分具体的代码和实现方式时,要多注意到细节,不要只能写出一个框架。
* 算法方面很薄弱的,最好多刷一刷,不然影响你的工资和成功率😯
* 在投递简历之前,最好通过各种渠道找到公司内部的人,先提前了解业务,也可以帮助后期优秀 offer 的决策。
* 要勇于说不,对于某些 offer 待遇不满意、业务不喜欢,应该相信自己,不要因为当下没有更好的 offer 而投降,一份工作短则一年长则 N 年,为了幸福生活要慎重选择!!!
喜欢这篇文章文章的小伙伴们点赞+转发支持,你们的支持是我最大的动力!