await Promise内部执行setTimeout定时器,提前clearTimeout,导致卡死的情况分析及解决方案

背景概述

在我们日常开发中,我们常常需要在某个地方暂停某个动作一段时间。这个时候,我们的通常做法是使用setTimeout,配合promise实现。也就是如下代码。

function delay(ms) {return new Promise((resolve, reject) => {setTimeout(() => {resolve('Delayed value');}, ms);});
}async function example() {console.log('Before delay');await delay(2000); // 等待Promise的resolve操作完成console.log('After delay');
}

但我们偶尔需要提前终止这个定时器。这时候我们会需要使用JavaScript 自带的clearTimeout方法,这个方法要求我们传入 timeoutId,也就是这个定时器的Id

const timeoutId = setTimeout(() => {}, ms)
clearTimeout(timeoutId)

遭遇问题

如上所述,我们在某个地方暂停某个动作一段时间。这个时候,我们的通常做法是使用setTimeout,配合promise实现。又需要提前终止这个定时器。我们普遍的做法是让一个外部变量接受这个setTimeout的返回值。然后在需要终止他的地方,调用clearTimeout,终止这个定时器。

let timeoutId = '';
function delay(ms) {const promise = new Promise((resolve, reject) => {timeoutId = setTimeout(() => {resolve("Delayed value");}, ms);});return promise;
}

或者是内部定义方法

function delay(ms) {let timeoutId; // 保存timeoutId的变量const promise = new Promise((resolve, reject) => {timeoutId = setTimeout(() => {resolve("Delayed value");}, ms);});// 添加一个stop方法,用于提前停止延迟操作promise.stop = () => {clearTimeout(timeoutId);};return promise;
}

但是这两种都有同样的一个问题

async function example() {console.log("Before delay");const promise = delay(2000); // 获取延迟操作的Promise对象setTimeout(() => {promise.stop(); // 提前停止延迟操作console.log("Stopped delay");}, 1000);await promise; // 等待Promise的resolve操作完成console.log("After delay");
}example();

在这里插入图片描述

后续代码的 console.log(“After delay”)就至此不会再被执行了。

原因分析

await紧跟一个没有resolve/reject的promise对象,则后续的代码不会被执行。举个小例子

async function a(){// 如果await后是promise对象 await new Promise(resolve => {console.log(66666)})console.log(1) // 这一行并不会被执行到
}
a();

也就是说这里的 await 所等待的 promise的状态永远是处于 pending 状态的。

我们上述的代码中的resolve()在setTimeout内部,当定时器被提前终止的时候,定时器内部的回调函数不会被调用,也就是resolve从此不会被任何东西调用。导致 promise永远处于pending状态,而await 永远等待这个pending状态的代码执行。则await后续代码永远不会被执行。

解决方法

我们可以使用AbortControllersetTimeout结合的方式来中断延迟操作,并在需要中断的时候调用abort方法。这样,中断操作后的代码就会执行,从而实现提前停止延迟操作。

在这里插入图片描述

AbortController通常用来终止web请求,和我们这个有异曲同工之妙。

解决代码如下

function delay() {const controller = new AbortController();const signal = controller.signal;const promise: any = new Promise((resolve, reject) => {const timeoutId = setTimeout(() => {resolve("Delayed value");}, 60000);signal.addEventListener("abort", () => {clearTimeout(timeoutId);resolve("Delayed value");});});promise.stop = () => {controller.abort();};return promise;
}async function example() {console.log('Before delay');const promise = delay(2000);setTimeout(() => {promise.stop();console.log('Stopped delay');}, 1000);await promise;console.log('After delay');
}example();

这样就能正常调用啦
在这里插入图片描述

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

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

相关文章

element上传图片,调取接口传值,参数FormData为空

需求 输入完reason,选完文件后,点击提交按钮后 调取接口。 遇到的问题 上传文件orderFile 字段一直为空 打印了发现,上传文件也是有值得。但是传到接口中就为空 原因 json里边不能放file,但是formData里可以放 file 也可以放…

Kotlin全方位-简单解析

Kotlin是一种现代化的静态类型编程语言,由JetBrains公司开发。它可以在Java虚拟机(JVM)上运行,并且可以与Java代码无缝地进行互操作。Kotlin旨在提供更简洁、更安全、更具表达力和更高效的编程语言。 Kotlin主要运用 Android开发…

AIGC ChatGPT 实现动态多维度分析雷达图制作

雷达图在多维度分析中是一种非常实用的可视化工具,主要有以下优势: 易于理解:雷达图使用多边形或者圆形的形式展示多维度的数据,直观易于理解。多维度对比:雷达图可以在同一张图上比较多个项目或者实体在多个维度上的…

OpenCV基础知识(9)— 视频处理(读取并显示摄像头视频、播放视频文件、保存视频文件等)

前言:Hello大家好,我是小哥谈。OpenCV不仅能够处理图像,还能够处理视频。视频是由大量的图像构成的,这些图像是以固定的时间间隔从视频中获取的。这样,就能够使用图像处理的方法对这些图像进行处理,进而达到…

openGauss学习笔记-52 openGauss 高级特性-LLVM

文章目录 openGauss学习笔记-52 openGauss 高级特性-LLVM52.1 适用场景52.2 非适用场景52.3 其他因素对LLVM性能的影响52.4 LLVM使用建议 openGauss学习笔记-52 openGauss 高级特性-LLVM openGauss借助LLVM(Low Level Virtual Machine)提供的库函数&…

【C++】—— C++11之线程库

前言: 在本期,我将给大家介绍的是 C11 中新引进的知识,即关于线程库的相关知识。 目录 (一)线程库的介绍 1、线程库的由来 2、线程库的简单介绍 (二)线程函数参数 (三&#xf…

window系统中如何判断是物理机还是虚拟机及VMPROTECT无法检测云主机

为什么要判断物理机,因为授权不能对虚拟机安装后的软件进行授权。虚拟机可以复制可以克隆,无法作为一个不可复制ID来使用。 总结了如何判断物理机: 1. 用systeminfo的系统型号。(注,有资料是看处理器和bios。但是我这…

List与String数组互转

一.List 转为 String 数组 1.使用toArray方法 public static void main(String[] args) {List<String> list Lists.newArrayList("1","2","3");// Java6以前版本String[] str1 list.toArray(new String[list.size()]);// Java6以后版本…

高并发场景加锁方式及存在的问题

在多线程高并发场景下&#xff0c;为了保证共享资源的正确性&#xff0c;通常会采用加锁的方式。关于加锁以及一些相关的问题&#xff0c;这里根据个人学习了解的做个汇总。 加锁方式&#xff1a; 1、JVM锁1.1 多例模式1.2 事务1.3 集群 2、MySQL悲观锁乐观锁2.1 悲观锁2.2 乐…

JavaScript模块化历程(二)

文章目录 4.模块化标准规范(ES Modules)4.1 如何使用ES6规范4.2 严格模式4.3 实际使用4.4 默认导出4.5 <scrpit>加载文件的顺序 参考文章 4.模块化标准规范(ES Modules) ES6 提供的模块化方案叫做 ES Module&#xff0c;简称 esm,现在我开始接触的基本就是这种规范了,写n…

leetcode做题笔记106. 从中序与后序遍历序列构造二叉树

给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 思路一&#xff1a;递归 struct TreeNode* createTreeNode(int val) {struct TreeNode* ret ma…

四信5G工业路由器赋能5G LAN全连接工厂建设

5G作为“新基建”之首&#xff0c;肩负着驱动国民经济转型升级、促进实体经济与数字经济深度融合、满足各行各业高质量通信服务需求的重任。 随着5G技术的更新迭代&#xff0c;各行各业对网络的可靠性&#xff0c;确定性等提出更高的需求&#xff0c;5G LAN作为3GPP R16标准定…

【CSS】网站 网格商品展示 模块制作 ( 清除浮动需求 | 没有设置高度的盒子且内部设置了浮动 | 使用双伪元素清除浮动 )

一、清除浮动需求 ( 没有设置高度的盒子且内部设置了浮动 ) 绘制的如下模块 : 在上面的盒子中 , 没有设置高度 , 只设置了一个 1215px 的宽度 ; 在列表中每个列表项都设置了 浮动 ; /* 网格商品展示 */ .box-bd {/* 处理列表间隙导致意外换行问题一排有 5 个 228x270 的盒子…

如何修改由 img 标签引入的 svg 图片颜色 (react环境)

网上试了好几个方法都不行&#xff0c;问了一下身边同事的处理方法&#xff0c;终于搞定了。话不多说&#xff0c;直接上代码&#xff1a; 此处是 jsx 中的图标引入 <img className{STYLE.contactIcon}onClick{() > {你的一些操作}} style{{WebkitMaskImage: url(${ite…

LibreOffice新一代的办公软件for Mac/Windows免费版

LibreOffice是一款免费、开源的办公软件套件&#xff0c;可在多个操作系统上运行&#xff0c;包括Windows、Mac和Linux。它提供了一系列功能强大的办公工具&#xff0c;包括文档处理、电子表格、演示文稿、数据库管理等。 LibreOffice的界面简洁直观&#xff0c;与其他流行的办…

【力扣每日一题】2023.8.26 汇总区间

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们一个有序数组&#xff0c;让我们把数组内的元素汇总区间&#xff0c;也就是说有一串数字是连续的&#xff0c;比如是 1 2 3 4…

idea启动正常,打成jar包时,启动报错

背景 自己写了个小程序&#xff0c;在idea中启动正常&#xff0c;达成jar包发布时&#xff0c;启动报错。 Caused by: java.sql.SQLException: unknown jdbc driver : at com.alibaba.druid.util.JdbcUtils.getDriverClassName(JdbcUtils.java:517) at com.alibaba.druid.pool…

用AI重构的钉钉,“钱”路在何方?

点击关注 文&#xff5c;郝 鑫&#xff0c;编&#xff5c;刘雨琦 钉钉2023年生态大会&#xff0c;离开了两年的无招&#xff0c;遇到了单飞9天的钉钉。 “做小钉钉、做好钉钉、做酷钉钉”&#xff0c;无招重申了钉钉的方向。 无招提到的三点&#xff0c;再加上“高质量增长”…

工厂模式简介

概念&#xff1a; 工厂模式&#xff08;Factory Pattern&#xff09;是一种创建型设计模式&#xff0c;它提供了一种封装对象实例化过程的方式&#xff0c;客户端只需要关注接口或抽象类&#xff0c;并由工厂类根据具体需求返回相应的实例。工厂模式将对象的创建与使用分离&am…

Linux下jenkins全量迁移到新服务器

文章目录 1、目的2、迁移1&#xff09;查看jenkins的主目录2&#xff09;登录要迁出的服务器打包3&#xff09;找到对应的war包4&#xff09;登录对应迁入服务&#xff0c;上传war包和打包的jenkins数据等5&#xff09;在新的服务器解压迁入的数据等&#xff0c;并查看端口是否…