Debug: setTimeout 使用做定时器时的错误函数传递方式

news/2024/11/13 14:03:57/文章来源:https://www.cnblogs.com/LinForest/p/18538810

MarkTime: 2024-05-24 10:41:26

LogTime: 2024-11-10 14:55:53


首先复习

setTimeout():
语法: let timeId = setTimeout(func|code, [delay_millisecond])
说明: 延时器. 延迟delay_millisecond后, 执行参数1setInterval(): 
语法: let timeId = setInterval(func|code, [delay_millisecond])
说明: 周期性执行器. 每隔delay_millisecond执行一次参数1

说明

问题

利用标识来判断是否执行下一次的 setTimeout函数,
原本写代码的时候想着的是:
   第一次的periodicTimerFunc() 执行后,
   如果1号还在录音,
   则等5s后开始下一次的 periodicTimerFunc() 执行
   但直接就执行了,
   并没有等待

其他补充

  • 版本相关:

    • vue: 2.6.14
    • js-audio-recorder: 1.0.7
  • 背景

    • 需求: 一边进行录音, 一边对录音的内容转义为中文输出到交互面板上

    • 说明:

      1. 以下代码  是当时写的 语音交互的第一版( js-audio-recorder1.0.7 ), 
        文档: https://recorder-api.zhuyuntao.cn/Recorder/event.html不支持 边转边录其实(没办法获取到中间数据), 
        所以先自己取巧了一下, 
        大体逻辑就是 启动完1号录音对象 再定时启动2号录音对象进行转录.存在明显 Bug (2号每次启动时, 会对录制正在进行中的1号造成干扰, 1号这个时候录制不到音频.=> 1号 完成录制导出的录音文件: 听感: 每隔几秒就很有一段人体感受很不舒适的段静默
        )
        
      2. 查阅了下, 
        找到比较新的大大也还在维护的 recorder-core1.3.24040900,
        支持了在启动 recorder 录音对象之后的实时回调函数 onProcess().
        那么之前的Bug, 最后采取的
        优化思路:在onProcess里实现边录边转,并在最后导出文件的时候 把 段音频数组 合并即可.源码、说明文档: https://github.com/xiangyuecn/Recorder
        

源码

<script>/* 省略了很多, 只是留下基础结构为说明*/import Recorder from 'js-audio-recorder';export default {data(){return {recorder: new Recorder({ // 1号录音对象sampleBits: 16, // 采样位数,支持 8 或 16,默认是16sampleRate: 16000, // 采样率,支持 11025、16000、22050、24000、44100、48000, 录音一般用16000numChannels: 2, // 声道,支持 1 或 2, 默认是1}),pRecorder: new Recorder({ // 2号录音对象 - 用来在1号启动的期间, 把定量的音频传输转义sampleBits: 16, // 采样位数,支持 8 或 16,默认是16sampleRate: 16000, // 采样率,支持 11025、16000、22050、24000、44100、48000, 录音一般用16000numChannels: 2, // 声道,支持 1 或 2, 默认是1}),isPeriodicTimerRun: false, // 是否启动周期调用识别}}, methods: {/*** 录音周期转义文字*/toPhoTranscri(){this.toStopPhoTranscri(); // 停止所有录音对象this.isPeriodicTimerRun = true;this.pRecorder.start();let cTime = '12345679';let periodicTimerFunc = (cTime) => {debuggerconsole.log(cTime);let wavResource = this.pRecorder.getWAV();let mp3Resource = this.convertToMp3('pRecorder', wavResource);this.pRecorder.stop();this.pRecorder.start(); // TODO 重新启动会有延迟let currentTime = new Date().formatStr('yyyy-MM-dd HH:mm:ss');let formData = this.convertBlobToMultipartFile(mp3Resource, `录音${currentTime}`);// blahblahblah... 省略一堆把 wav转为mp3文件之后, 调用接口处理识别为中文后返回, 并后续渲染的逻辑if (this.isPeriodicTimerRun){ // isPeriodicTimerRun 是如果用户点击了"停止录音"的按钮之后会=false的控制变量debuggerthis.periodicTimer = setTimeout(periodicTimerFunc(currentTime), 5000);}}this.periodicTimer = setTimeout(periodicTimerFunc(cTime), 5000);},/*** 停止所有录音对象行为、一些初始化行为*/toStopPhoTranscri(){ /* ... */ },/*** 将wav文件转换为mp3格式*/convertToMp3(){ /* ... */ },/*** 将blob文件转换为form表单对象*/convertBlobToMultipartFile(){ /* ... */ },}}
</script>

解决

嘿嘿我是笨蛋, 用来直接做参数传递肯定就直接一下子执行了啊, 会把执行的结果当作传参再延迟 5s 后执行.

所以需要改变一下写法,

让它在5s后再执行 periodicTimerFunc().

使用箭头函数, 去创建一个新的函数, 只是函数内部执行的是 periodicTimerFunc(),

这样子当定时器在 5s 后被调用的时候才会去执行函数内部的内容.

setTimeout(periodicTimerFunc(cTime), 5000) => setTimeout(() => periodicTimerFunc(cTime), 5000)


<script>import Recorder from 'js-audio-recorder';export default {data(){return {recorder: new Recorder({ // 1号录音对象sampleBits: 16, // 采样位数,支持 8 或 16,默认是16sampleRate: 16000, // 采样率,支持 11025、16000、22050、24000、44100、48000, 录音一般用16000numChannels: 2, // 声道,支持 1 或 2, 默认是1}),pRecorder: new Recorder({ // 2号录音对象 - 用来在1号启动的期间, 把定量的音频传输转义sampleBits: 16, // 采样位数,支持 8 或 16,默认是16sampleRate: 16000, // 采样率,支持 11025、16000、22050、24000、44100、48000, 录音一般用16000numChannels: 2, // 声道,支持 1 或 2, 默认是1}),isPeriodicTimerRun: false, // 是否启动周期调用识别}}, methods: {/*** 录音周期转义文字*/toPhoTranscri(){this.toStopPhoTranscri();this.isPeriodicTimerRun = true;this.pRecorder.start();let cTime = '';let periodicTimerFunc = (cTime) => {let wavResource = this.pRecorder.getWAV();let mp3Resource = this.convertToMp3('pRecorder', wavResource);this.pRecorder.stop();this.pRecorder.start();let currentTime = new Date().formatStr('yyyy-MM-dd HH:mm:ss');let formData = this.convertBlobToMultipartFile(mp3Resource, `录音${currentTime}`);// blahblahblah... 省略一堆把 wav转为mp3文件之后, 调用接口处理识别为中文后返回, 并后续渲染的逻辑if (this.isPeriodicTimerRun){this.periodicTimer = setTimeout(() => periodicTimerFunc(currentTime), 5000); // (ง •_•)ง 就是这里用箭头函数改一下}}this.periodicTimer = setTimeout(periodicTimerFunc(cTime), 5000); // 这里的确需要 periodicTimerFunc() 立刻执行, 即第一次启动入口},/*** 停止所有录音对象行为、一些初始化行为*/toStopPhoTranscri(){ /* ... */ },/*** 将wav文件转换为mp3格式*/convertToMp3(){ /* ... */ },/*** 将blob文件转换为form表单对象*/convertBlobToMultipartFile(){ /* ... */ },}}
</script>

↓ 2024-05-24 10:41:26 至 2024-05-24 10:41:37 中间的时间过长是因为打了debugger断点被我人为中断了


总结

直接传递函数调用会导致函数立即执行, 并将结果传递给 setTimeout , 而不是传递函数本身, 所以应该传递的是返回函数调用的箭头函数, 即传递一个函数引用. 这样子 setTimeout 在延迟时间结束后才会执行被引用的函数.

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

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

相关文章

Debug: calc() 未生效 = 内嵌样式表达式需使用空格分隔

MarkTime: 2024-06-25 17:10 LogTime: 2024-11-09 13:58:02结论calc()内的表达式 需要使用 空格分隔符, 即 更正 calc(100%-100px-10px); => calc(100% - 100px - 10px); 即可源<!-- 原错误代码 --> <div class="layout-search" style="width: 100%…

[云研发]腾讯云cloudstudio使用教程-记录1

cloudstudio在vscode中新建终端,使用nvidia-smi查看显卡与gpu情况,可知当前使用的显卡是T4的,显存有15GTalk is cheap. Show me the code

rip

题目链接:rip。 IDA 打开附件,进入到 main 函数,反编译后如下。留意到存在 gets 函数,因此存在栈溢出漏洞,经过动态调试,确定在输入 0x17 个字符后,即可覆盖到返回地址。同时,留意到存在 fun 函数,如下。因此,直接将程序执行流劫持到 fun 函数,即可 GetShell(此处需…

test_your_nc

题目链接:test_your_nc。 打开附件,进入 main 函数,IDA 反编译如下。因此直接连接即可 GetShell。

【docker应用】从Docker(k8s)镜像或者容器里提取jar包

引言 在docker或者k8s上运行了第三方的应用,很多时候我们都想知道运行流程,一般都会docker或者k8s容器中获取jar包。 那么该如何把里面的jar包提取出来呢? 其实有两种方式,分别为: 从镜像信息获取 进入容器获取从镜像信息获取 首先,查看镜像: docker image ls |grep <…

充电桩普遍选用芯海CSE7761集成3路ADC的免校准单相计量芯片

CSE7761是一款单相多功能电能计量芯片,工作于 3.579MHz 时钟频率,其内部集成了 3 路 sigmadelta ADC、功率计算器、能量-频率转换器、一路 SPI 接口、一路 UART 接口。适用于充电桩、单相多功能电能表、智能插座、智能家电等应用.CSE7761 设计用于精确计算电压有效值、电流有…

喝个水也要整智能家居?

ChatGPT对文章的摘要 这篇博客讲述了作者在家庭日常用水管理方面的改进经历。由于家里用水量增多,作者不断优化解决方案,从最初用农夫山泉桶装水,到购买反渗透净水机,再到通过智能化手段 简化补水流程。过程中,作者不断提高设备自动化程度,最终实现了全自动化补水,并且详…

基于FPGA的256QAM基带通信系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR

1.算法仿真效果 vivado2019.2仿真结果如下(完整代码运行后无水印):设置SNR=40db:将数据导入matlab,显示其星座图:设置SNR=32db:将数据导入matlab,显示其星座图:设置SNR=24db:将数据导入matlab,显示其星座图:系统RTL结构如下:仿真操作步骤可参考程序配套的操作视频…

产业园区,被逼急了

这几年传统的地产开发业务遇到了各种各样的困境,许多房企转而开始积极布局多元化业务,业内的“去地产化”运动也愈演愈烈。 在这个时代背景下,产业园开发运营赛道迎来了一波热度爆发,吸引着众多房企和其他多元化主体的参与。那么,在日益升高的关注度与参与度之下,产业地产…

寂寂冬夜

引言 没错,本文的标题是嘉然学姐最喜欢的动漫《白色相簿2》中的插曲。 今天,chino 的 XCPC 最后一站——杭州站也结束了。(又浪费一年) 于是姑且乱写一番,也算是留下自己虚度光阴的罪证。 第一站 CCPC 哈尔滨 第一站是 CCPC 哈尔滨站,周六中午和 CD, BE, Sakura, Chen_jr 吃…

2024年11月10日重装系统后安装的软件

激活 Win11 双击开始激活:点击开始:激活完成:IDEA 2024 资源来自考拉软件:https://www.rjctx.com/41804.html

基于game-based算法的动态频谱访问matlab仿真

1.算法运行效果图预览 (完整程序运行后无水印)展示了负载因子P和次级传输功率不同的HPE。从图中可以看出,随着|hP E|扩大,用户P更好的为二级用户分配更多的频谱机会,以便刺激二级用户传输更多的干扰功率,因此,导致ρ的减少和Psu的增加。不同方案下不同用户P信噪比下的保密率。…