当前位置:首页 > 科技  > 软件

八个关于 Promise 的高级用途的技巧

来源: 责编: 时间:2024-01-02 17:27:34 283观看
导读我发现很多人只知道如何常规地使用promise。在js项目中,promise的使用应该是必不可少的,但我发现在同事和面试官中,很多中级以上的前端仍然坚持promiseInst.then()、promiseInst.catch()、Promise等常规用法等等。即使是

我发现很多人只知道如何常规地使用promise。C0V28资讯网——每日最新资讯28at.com

C0V28资讯网——每日最新资讯28at.com

在js项目中,promise的使用应该是必不可少的,但我发现在同事和面试官中,很多中级以上的前端仍然坚持promiseInst.then()、promiseInst.catch()、Promise等常规用法等等。即使是 async/await 他们也只知道它但不知道为什么要使用它。C0V28资讯网——每日最新资讯28at.com

但实际上,Promise 有很多巧妙的高级用法,并且一些高级用法在 alova 请求策略库内部也被广泛使用。C0V28资讯网——每日最新资讯28at.com

现在,我将与大家分享8个高级使用技巧。希望这些技巧能够对你有所帮助,现在,我们就开始吧。C0V28资讯网——每日最新资讯28at.com

1. Promise数组的串行执行

例如,如果你有一组接口需要串行执行,你可能首先想到使用await。C0V28资讯网——每日最新资讯28at.com

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

如果使用promise,可以使用then函数串联多个promise,实现串行执行。C0V28资讯网——每日最新资讯28at.com

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 范围之外更改状态

假设你有多个页面,其功能要求在允许使用之前收集用户信息。 点击使用某个功能之前,会弹出一个弹框进行信息收集。 你会如何实施这个?C0V28资讯网——每日最新资讯28at.com

以下是不同级别前端同学的实现思路:C0V28资讯网——每日最新资讯28at.com

初级前端:我写一个模态框,然后复制粘贴到其他页面。 效率非常高!C0V28资讯网——每日最新资讯28at.com

中级前端:这个不好维护。 我们需要单独封装这个组件,并在需要的页面引入!C0V28资讯网——每日最新资讯28at.com

高级前端:安装任何密封的东西! ! ! 把方法调用写在所有页面都可以调用的地方不是更好吗?C0V28资讯网——每日最新资讯28at.com

想要了解高级前端是如何实现的,以vue3为例,看一下下面的例子。C0V28资讯网——每日最新资讯28at.com

<!-- 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 followingprovide('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就可以通过直接调用模态框来轻松获取用户填写的数据。C0V28资讯网——每日最新资讯28at.com

<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组件库中封装常用组件的一种方式。C0V28资讯网——每日最新资讯28at.com

3. async/await 的替代用法

很多人只知道它是用来在调用await时接收async函数的返回值的,却不知道async函数它实际上是一个返回promise的函数。 例如,以下两个函数是等效的:C0V28资讯网——每日最新资讯28at.com

const fn1 = async () => 1;const fn2 = () => Promise.resolve(1);fn1(); // Also returns a promise object with a value of 1

在大多数情况下,await 会跟随 Promise 对象并等待它完全填充。 因此,下面的 fn1 函数 wait 也是等价的:C0V28资讯网——每日最新资讯28at.com

await fn1();const promiseInst = fn1();await promiseInst;

然而,await也有一个鲜为人知的秘密。 当它后面跟的值不是promise对象时,它会用promise对象包装该值,所以await后面的代码必须异步执行。 例子:C0V28资讯网——每日最新资讯28at.com

Promise.resolve().then(() => {  console.log(1);});await 2;console.log(2);//Print order bits: 1 2

相当于C0V28资讯网——每日最新资讯28at.com

Promise.resolve().then(() => {  console.log(1);});Promise.resolve().then(() => {  console.log(2);});

4. 承诺实施请求共享

当一个请求已经发出但尚未得到响应时,再次发出相同的请求,就会造成请求的浪费。 此时,我们可以将第一个请求的响应与第二个请求共享。C0V28资讯网——每日最新资讯28at.com

request('GET', '/test-api').then(response1 => {  // ...});request('GET', '/test-api').then(response2 => {  // ...});

上述两个请求实际上只发送一次,同时收到相同的响应值。C0V28资讯网——每日最新资讯28at.com

那么,请求共享有哪些使用场景呢? 我认为有以下三个:C0V28资讯网——每日最新资讯28at.com

  • 当页面渲染多个内部组件同时获取数据时;
  • 提交按钮未禁用且用户连续多次点击提交按钮;
  • 预加载数据的情况下,预加载完成之前进入预加载页面;

这也是alova的高级功能之一。 要实现请求共享,需要使用promise的缓存功能,即一个promise对象可以通过多次await获取数据。 简单的实现思路如下:C0V28资讯网——每日最新资讯28at.com

const pendingPromises = {};function request(type, url, data) {   // Use the request information as the only request key to cache the promise object being requested   //Requests with the same key will reuse 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;}

上述两个请求实际上只发送一次,同时收到相同的响应值。C0V28资讯网——每日最新资讯28at.com

那么,请求共享有哪些使用场景呢? 我认为有以下三个:C0V28资讯网——每日最新资讯28at.com

  • 当页面渲染多个内部组件同时获取数据时;
  • 提交按钮未禁用且用户连续多次点击提交按钮;
  • 预加载数据的情况下,预加载完成之前进入预加载页面;

这也是alova的高级功能之一。 要实现请求共享,需要使用promise的缓存功能,即一个promise对象可以通过多次await获取数据。 简单的实现思路如下:C0V28资讯网——每日最新资讯28at.com

const promise = new Promise((resolve, reject) => {  resolve();  reject();});

正确答案是已满状态。 我们只需要记住,一旦待处理的promise从一种状态转移到另一种状态,就无法更改。 因此,例子中是先转为fulfilled状态,然后reject()就不会再转为rejected状态。C0V28资讯网——每日最新资讯28at.com

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

一句话概括就是,上面三个函数都会返回一个新的promise包装对象。 包装后的值是执行回调函数的返回值。 如果回调函数抛出错误,它将包装拒绝状态承诺。 似乎不太容易理解,我们来看一个例子:C0V28资讯网——每日最新资讯28at.com

我们可以将它们一一复制到浏览器控制台并运行它们以帮助理解。C0V28资讯网——每日最新资讯28at.com

// then functionPromise.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 functionPromise.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

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

当请求发生错误时,会触发 Promise 的 then 的第二个回调函数和 catch。 乍一看没有区别,但实际上前者无法捕获then当前第一个回调函数中抛出的错误,但catch可以。C0V28资讯网——每日最新资讯28at.com

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"});

原理就如上一点所说的。 catch 函数是在 then 函数返回的处于拒绝状态的 Promise 上调用的,因此它的错误自然可以被捕获。C0V28资讯网——每日最新资讯28at.com

8.(最终)Promise实现koa2洋葱中间件模型

koa2框架引入了洋葱模型,可以让你的请求像剥洋葱一样一层层进去,再一层层出来,从而实现请求前后处理的统一。C0V28资讯网——每日最新资讯28at.com

C0V28资讯网——每日最新资讯28at.com

我们来看一个简单的 koa2 洋葱模型:C0V28资讯网——每日最新资讯28at.com

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行左右的代码就实现了。 如有雷同,纯属巧合。C0V28资讯网——每日最新资讯28at.com

接下来我们分析一下C0V28资讯网——每日最新资讯28at.com

注:以下内容对新手不友好,请谨慎阅读。C0V28资讯网——每日最新资讯28at.com

首先先保存中间件函数,在listen函数中收到请求后调用洋葱模型执行。C0V28资讯网——每日最新资讯28at.com

function action(koaInstance, ctx) {  // ...}class Koa {   middlewares = [];   use(mid) {     this.middlewares.push(mid);   }   listen(port) {     // Pseudocode simulates receiving request     http.on('request', ctx => {       action(this, ctx);     });   }}

收到请求后,从第一个中间件开始串行执行next之前的前置逻辑。C0V28资讯网——每日最新资讯28at.com

//Start to start middleware callfunction action(koaInstance, ctx) {   let nextMiddlewareIndex = 1; // Identifies the next middleware index to be executed   //Define next function   function next() {     // Before peeling the onion, calling next will call the next middleware function     const nextMiddleware = middlewares[nextMiddlewareIndex];     if (nextMiddleware) {       nextMiddlewareIndex++;       nextMiddleware(ctx, next);     }   }   //Start execution from the first middleware function and pass in the ctx and next functions   middlewares[0](ctx, next);}

处理next之后的post逻辑C0V28资讯网——每日最新资讯28at.com

function action(koaInstance, ctx) {   let nextMiddlewareIndex = 1;   function next() {     const nextMiddleware = middlewares[nextMiddlewareIndex];     if (nextMiddleware) {       nextMiddlewareIndex++;       // A return is also added here to allow the execution of the middleware function to be executed in series from back to front using promises (it is recommended to understand this return repeatedly)       return Promise.resolve(nextMiddleware(ctx, next));     } else {       // When the pre-logic of the last middleware is executed, return the fullyfilled promise and start executing the post-logic after next.       return Promise.resolve();     }   }   middlewares[0](ctx, next);}

至此,一个简单的洋葱模型就已经实现了。C0V28资讯网——每日最新资讯28at.com

总结

以上就是我今天想与你分享的8个关于Promise的高级用途的全部内容,如果你觉得有用的话,请记得点赞我,关注我,并将这个内容分享给你的小伙伴们,也许能够帮助到他。C0V28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-56393-0.html八个关于 Promise 的高级用途的技巧

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 九部门:推广农村客运车辆代运邮件快件,拓展“农村客货邮 +”

下一篇: Cython库:从基本用法到高级用法

标签:
  • 热门焦点
  • Redmi Pad评测:红米充满野心的一次尝试

    从Note系列到K系列,从蓝牙耳机到笔记本电脑,红米不知不觉之间也已经形成了自己颇有竞争力的产品体系,在中端和次旗舰市场上甚至要比小米新机的表现来得更好,正所谓“大丈夫生居
  • 六大权益!华为8月服务日开启:手机免费贴膜、维修免人工费

    8月5日消息,一年一度的华为开发者大会2023(Together)日前在松山湖拉开帷幕,与此同时,华为8月服务日也式开启,到店可享六大专属权益。华为用户可在华为商城Ap
  • 印度登月最关键一步!月船三号今晚进入环月轨道

    8月5日消息,据印度官方消息,月船三号将于北京时间今晚21时30分左右开始近月制动进入环月轨道。这是该探测器能够成功的最关键步骤之一,如果成功将开始围
  • 在线图片编辑器,支持PSD解析、AI抠图等

    自从我上次分享一个人开发仿造稿定设计的图片编辑器到现在,不知不觉已过去一年时间了,期间我经历了裁员失业、面试找工作碰壁,寒冬下一直没有很好地履行计划.....这些就放在日
  • 一文搞定Java NIO,以及各种奇葩流

    大家好,我是哪吒。很多朋友问我,如何才能学好IO流,对各种流的概念,云里雾里的,不求甚解。用到的时候,现百度,功能虽然实现了,但是为什么用这个?不知道。更别说效率问题了~下次再遇到,
  • 使用AIGC工具提升安全工作效率

    在日常工作中,安全人员可能会涉及各种各样的安全任务,包括但不限于:开发某些安全工具的插件,满足自己特定的安全需求;自定义github搜索工具,快速查找所需的安全资料、漏洞poc、exp
  • 慕岩炮轰抖音,百合网今何在?

    来源:价值研究所 作者:Hernanderz&ldquo;难道就因为自己的一个产品牛逼了,从客服到总裁,都不愿意正视自己产品和运营上的问题,选择逃避了吗?&rdquo;这一番话,出自百合网联合创
  • 2天涨粉255万,又一赛道在抖音爆火

    来源:运营研究社作者 | 张知白编辑 | 杨佩汶设计 | 晏谈梦洁这个暑期,旅游赛道彻底火了:有的「地方」火了&mdash;&mdash;贵州村超旅游收入 1 个月超过 12 亿;有的「博主」火了&m
  • 联想的ThinkBook Plus下一版曝光,键盘旁边塞个平板

    ThinkBook Plus 是联想的一个特殊笔记本类别,它在封面放入了一块墨水屏,也给人留下了较为深刻的印象。据有人爆料,联想的下一款 ThinkBook Plus 可能更特殊,它
Top