JavaScript 如何中止Promise

news2024/12/24 9:01:30

目录

方法 1:使用新的 Promise.withResolvers()

方法 2:使用 AbortController


在 JavaScript 中,你可能已经知道如何取消请求:对于 XHR 可以使用 xhr.abort() ,对于 fetch 可以使用 signal 。但是你如何取消一个普通的 Promise 呢?

目前,JavaScript 的 Promise 本身并不提供取消常规 Promise 的 API。因此,我们接下来要讨论的是如何丢弃 / 忽略 Promise 的结果。

方法 1:使用新的 Promise.withResolvers()

之前写法

let resolve, reject;

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

现在我们可以

 const { promise, resolve, reject } = Promise.withResolvers();

因此我们可以利用这一点来暴露一个名为 “cancel” 的方法:

const buildCancelableTask = <T>(asyncFn: () => Promise<T>) => {
   let rejected = false;
   const { promise, resolve, reject } = Promise.withResolvers<T>();

   return {
     run: () => {
       if (!rejected) {
         asyncFn().then(resolve, reject);
       }

       return promise;
     },

     cancel: () => {
       rejected = true;
       reject(new Error('CanceledError'));
     },
   };
 };

测试代码

 const sleep = (ms: number) => new Promise(res => setTimeout(res, ms));

 const ret = buildCancelableTask(async () => {
   await sleep(1000);
   return 'Hello';
 });

 (async () => {
   try {
     const val = await ret.run();
     console.log('val: ', val);
   } catch (err) {
     console.log('err: ', err);
   }
 })();

 setTimeout(() => {
   ret.cancel();
 }, 500);

这里,将任务预设为至少耗时1000毫秒,但我们在接下来的500毫秒内取消了任务,所以会看到:

注意,这并不是真正的取消,而是提前拒绝。原来的 asyncFn() 将继续执行,直到解析或拒绝为止,但这并不重要,因为用 Promise.withResolvers<T>() 创建的 Promise 已经被拒绝了。 

 

方法 2:使用 AbortController

就像我们取消获取请求一样,我们也可以实现一个监听器来实现提前拒绝。它看起来是这样的:

const buildCancelableTask = <T>(asyncFn: () => Promise<T>) => {
   const abortController = new AbortController();

   return {
     run: () =>
       new Promise<T>((resolve, reject) => {
         const cancelTask = () => reject(new Error('CanceledError'));

         if (abortController.signal.aborted) {
           cancelTask();
           return;
         }

         asyncFn().then(resolve, reject);

         abortController.signal.addEventListener('abort', cancelTask);
       }),

     cancel: () => {
       abortController.abort();
     },
   };
 };

它具有与上述相同的效果,但使用的是 AbortController。你可以在此处使用其他监听器,但 AbortController 提供了额外好处,即如果你多次调用 cancel ,它不会多次触发 'abort' 事件。

基于此代码,我们可以进一步构建可取消的获取操作。这在需要连续请求的场景下非常有用,例如您可能希望丢弃之前的请求结果并使用最新的请求结果。

 const buildCancelableFetch = <T>(
   requestFn: (signal: AbortSignal) => Promise<T>,
 ) => {
   const abortController = new AbortController();

   return {
     run: () =>
       new Promise<T>((resolve, reject) => {
         if (abortController.signal.aborted) {
           reject(new Error('CanceledError'));
           return;
         }

         requestFn(abortController.signal).then(resolve, reject);
       }),

     cancel: () => {
       abortController.abort();
     },
   };
 };
 
 const ret = buildCancelableFetch(async signal => {
   return fetch('http://localhost:5000', { signal }).then(res =>
     res.text(),
   );
 });
 
 (async () => {
   try {
     const val = await ret.run();
     console.log('val: ', val);
   } catch (err) {
     console.log('err: ', err);
   }
 })();
 
 setTimeout(() => {
   ret.cancel();
 }, 500);

请注意,这不会影响服务器处理逻辑;它只会导致浏览器拒绝 / 取消请求,换句话说,如果你发送 POST 请求以更新用户信息,它仍然可能生效。因此,这种方法更常用于在获取新数据时发送 GET 请求的场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1925974.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络技术相关知识概念

网络技术&#xff1a; 进程&#xff08;Process&#xff09; 定义&#xff1a;进程是程序的一次执行过程&#xff0c;它有自己的内存空间和系统资源&#xff08;资源独立&#xff09;。特性&#xff1a; 每个进程都有唯一的PID&#xff08;进程ID&#xff09;。进程间通信&am…

6、evil box one

低—>中 目标&#xff1a;获取root权限以及2个flag 主机发现 靶机 192.168.1100.40 或者使用fping -gaq 192.168.100.1/24发现主机使用ping的方式。 端口扫描 发现开放了22和80 可以使用-A参数&#xff0c;-A参数会得到更多的扫描细节 访问80端口就是一个apache的基本的…

微服务-注册中心

一. 分布式系统架构与微服务 分布式系统架构和微服务是现代软件开发中常见的两种概念&#xff0c;它们通常结合使用来构建灵活、可扩展和高效的应用程序。 分布式系统架构&#xff1a; 分布式系统架构是指将一个单一的应用程序或服务拆分成多个独立的部分&#xff0c;这些部分…

讲讲 JVM 的内存结构(附上Demo讲解)

讲讲 JVM 的内存结构 什么是 JVM 内存结构&#xff1f;线程私有程序计数器​虚拟机栈本地方法栈 线程共享堆​方法区​注意永久代​元空间​运行时常量池​直接内存​ 代码详解 什么是 JVM 内存结构&#xff1f; JVM内存结构分为5大区域&#xff0c;程序计数器、虚拟机栈、本地…

50、haproxy+keepalive+nginx

keepalivehaproxy 客户端&#xff1a;192.168.168.21haproxy1&#xff1a;192.168.168.43haproxy2&#xff1a;192.168.168.44vip&#xff1a;192.168.168.100nginx1:192.168.168.31nginx2:192.168.168.32haproxykeepalive做高可用nginx做后台haproxy1haproxy2一起操作&#x…

实验发现AI提高了个人创造力,但降低了整体创造力

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

从链表中移除在数组中存在的节点 | 力扣题解

⭐简单说两句⭐ ✨ 正在努力的小叮当~ &#x1f496; 超级爱分享&#xff0c;分享各种有趣干货&#xff01; &#x1f469;‍&#x1f4bb; 提供&#xff1a;模拟面试 | 简历诊断 | 独家简历模板 &#x1f308; 感谢关注&#xff0c;关注了你就是我的超级粉丝啦&#xff01; &a…

【自监督学习】iBOT in ICLR 2022

一、引言 论文&#xff1a; iBOT&#x1f916;: Image BERT Pre-Training with Online Tokenizer 作者&#xff1a; ByteDance 代码&#xff1a; iBOT 注意&#xff1a; 该方法是在另一个自监督预训练方法基础上的改进&#xff0c;学习之前建议掌握DINO。 特点&#xff1a; 对…

数据结构之初始二叉树(1)

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;数据结构&#xff08;Java版&#xff09; 目录 树型结构 树的概念 与树的有关概念 树的表示形式 树的应用 二叉树 概念 两种特殊的…

MFC流的形式读取图片

1.基于对话框布置控件 2.给控件绑定变量 3.给按钮控件添加响应函数 void CMFC流的形式读取图片Dlg::OnBnClickedButton1() {// TODO: 在此添加控件通知处理程序代码//HDC mECGDC; // 设备描述表句柄//CPen mECGDrawPen; // ECG波形画笔//RECT mECGRect; // 在该矩形区域内画…

Three.js相机简明教程

相机校准是 3D 计算机图形学中的一个基本概念&#xff0c;涉及设置虚拟相机以模拟真实世界相机的视角和行为。在 Three.js&#xff08;一种流行的 3D 渲染 JavaScript 库&#xff09;中&#xff0c;了解相机校准对于创建逼真且身临其境的 3D 场景至关重要。在本文中&#xff0c…

AIGC是什么,与AI绘画有什么关系,一篇文章带你了解AI绘画的前世今生

在讲解AIGC和AI绘画之前&#xff0c;我们先看看什么是AI以及AI的历史。 AI历史发展轨迹 什么是人工智能 人工智能(Artificial intelligence&#xff0c;简称AI)亦称机器智能&#xff0c;指由人制造出来的机器所表现出来的智能。通常人工智能是指用普通计算机程序来呈现人类智…

ConfigMap-secrets-静态pod

一.ConfigMap 1.概述 ConfigMap资源&#xff0c;简称CM资源&#xff0c;它生成的键值对数据&#xff0c;存储在ETCD数据库中 应用场景&#xff1a;主要是对应用程序的配置 pod通过env变量引入ConfigMap&#xff0c;或者通过数据卷挂载volume的方式引入ConfigMap资源 官方解释…

成为git砖家(1): author 和 committer 的区别

大家好&#xff0c;我是白鱼。一直对 git author 和 committer 不太了解&#xff0c; 今天通过 cherry-pick 的例子搞清楚了区别。 原理 例如我克隆了著名开源项目 spdlog 的源码&#xff0c; 根据某个历史 commit A 创建了分支&#xff0c; 然后 cherry-pick 了这个 commit …

240710_昇思学习打卡-Day22-条件随机场

240710_昇思学习打卡-Day22-条件随机场 在正式开始LSTMCRF序列标注之前&#xff0c;我们先来了解一下条件随机场&#xff0c;以下仅做简单介绍。 CRF全称Conditional Random Field&#xff0c;按照名字来理解&#xff0c;条件随机&#xff0c;随机输入&#xff0c;条件输出。…

vue中父子传递属性值

1、父传子属性值 自定义图库组件 在add.vue中应用tuku组件并给默认值 效果 2、 子传父&#xff0c;逆向赋值 add.vue和第一问中一样 修改tuku组件&#xff0c;传值给add.vue 3、多个传递 效果&#xff1a; 点击两个修改按钮后 4、使用defineModel简化父子传值 其他代码跟…

使用Tkinter库设计实现的中小学校疫情防控入校人员登记检测系统

Tkinter简介 Tkinter是Python标准库中用于GUI图形用户界面开发的工具包&#xff0c;它是基于Tcl/Tk的封装&#xff0c;提供了大量预定义的控件&#xff0c;如按钮、文本框、标签等&#xff0c;非常适合快速原型开发和小型应用的构建。本文将通过一个具体的案例——“中小学校疫…

【java】力扣 合并k个升序链表

文章目录 题目链接题目描述思路代码 题目链接 23.合并k个升序链表 题目描述 给你一个链表数组&#xff0c;每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中&#xff0c;返回合并后的链表 思路 我在这个题里面用到了PriorityQueue(优先队列) 的知识 Prio…

鸿蒙语言基础类库:【@system.app (应用上下文)】

应用上下文 说明&#xff1a; 从API Version 7 开始&#xff0c;该接口不再维护&#xff0c;推荐使用新接口。本模块首批接口从API version 3开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 import app from system.app;app.getInfo …

MFC之对话框--重绘元文件

文章目录 实现示例展示需要绘制的窗口/位置控件位置更新下一次示例粗细滑动部分更新 重绘元文件&#xff08;窗口变化内容消失&#xff09;方法一&#xff1a;使用元文件方法二&#xff1a;兼容设备方法三&#xff1a;使用自定义类存储绘图数据除画笔外功能处理画笔功能处理 保…