谈谈JavaScript异步代码优化

别再为Power BI瀑布图发愁了!用这个DAX公式+堆积柱状图,5分钟搞定现金流量表可视化 本文介绍了一种使用DAX公式和堆积柱状图快速实现Power BI现金流量表可视化的高效方法。通过详细的步骤和代码示例,帮助财务分析人员5分钟内完成专业级报表制作,解决传统瀑布图配置复杂、灵活性差的问题,显著提升工作效率。 阅读详情

(点击上方公众号,可快速关注)

前言

在实际编码中,我们经常会遇到Javascript代码异步执行的场景,比如ajax的调用、定时器的使用等,在这样的场景下也经常会出现这样那样匪夷所思的bug或者糟糕的代码片段,那么处理好你的Javascript异步代码成为了异步编程至关重要的前提。下面我们从问题出发,一步步完善你的异步代码。

异步问题

1. 回调地狱

首先,我们来看下异步编程中最常见的一种问题,便是回调地狱。它的出现是由于异步代码执行时间的不确定性及代码间的依赖关系引发的,比如:

// 一个动画结束后,执行下一个动画,下一个动画结束后再执行下一个动画
$('#box').animate({width: '100px'}, 1000, function(){
    $('#box').animate({height: '100px'}, 1000, function(){
        $('#box').animate({left: 100}, 1000);
    });
});

由于我们不知道第一个动画什么时候开始或者什么时候结束,所以我们把第二个动画的执行内容放到了第一个动画的结束事件里,把第三个动画放到了第二个动画的结束事件里,这时候如果有很多这样的动画,那么就会形成回调地狱。

2. 捕获异常

除了回调地狱,如果我们需要在异步代码中捕获异常也比较麻烦,可能需要手动配置捕获方法:

try {
    throw new Error('fail');
} catch (e) {
    console.log(e);
}

这样的代码书写明显不是我们想要的,不仅不利于维护,而且也在一定程度上违背了良好的Javascript编码规范。

解决方案

那么我们如何优雅的写好我们的异步代码呢?我主要列了以下5种常见方案:

1. callback

callback顾名思义便是回调,但并不是将回调内容放在异步方法里,而是放到外部的回调函数中,比如问题1的代码我们通过callback可以变成这样:

$('#box').animate({width: '100px'}, 1000, autoHeight);

function autoHeight() {
    $('#box').animate({height: '100px'}, 1000, autoLeft);
}

function autoLeft() {
    $('#box').animate({left: 100}, 1000);
}

如此我们看似异步的代码变成了同步的写法,避免了层层嵌套的写法,看上去也流畅了很多。同时使用callback也是异步编程最基础和核心的一种解决思路。

2. Promise

基于callback,Promise目前也被广泛运用,其是异步编程的一种解决方案,比传统的回调函数解决方案更合理和强大。相信了解ES6的同学肯定不会陌生。

比如我们现在有这样一个场景,我们需要异步加载一张图片,在图片加载成功后做一些操作,这里我不想用回调函数或者将逻辑写在图片的成功事件里,那么用Promise我们可以这样写:

let p = new Promise((resolve, reject) => {
    let img = new Image(); // 创建图片对象
    
    // 图片加载成功事件
    img.onload = function() {
        resolve(img);  // 输出图片对象
    
    };
        
    // 图片加载失败事件
    img.onerror = function() {
        reject(new Error('load error')); // 输出错误
    };
    
    img.src = 'xxx'; // 图片路径
});

// Promise then回调
p
.then(result => {
    $('#box').append(result); // 成功后我们把图片放到页面上
})
.catch(error => {
    console.log(error); // 打印错误
})

通过Promise我们把图片构建加载的逻辑和成功或失败后的处理逻辑拆分了开来,将回调函数的嵌套,改成链式调用,同时使用Promise的catch事件回调后异常捕获也变得十分方便。

当然如果要等待多个异步请求完成执行某些操作,可以使用Promise.all方法,如:

let p = Promise.all([p1, p2, p3]); // 其中p1、p2、p3都是Promise实例

p.then(result => console.log(result));

当然Promise也有其相应的缺点,比如下一个then回调只能获取上一个then返回的数据,不能跨层获取,同时大量的then回调也会使代码不容易维护。

3. Generator

与Promise一样,Generator 函数也是 ES6 提供的一种异步编程解决方案,其会返回一个遍历器对象,异步任务需要暂停的地方我们可以使用yield语句,比如:

function* getData() {
    let result = yield fetch("xxx"); // 调用ajax,yield命令后面只能是 Thunk 函数或 Promise 对象
    
    console.log(result);
}
    
    
// 执行
let g = getData();
let result = g.next(); // { value: [object Promise], done: false }
    
    
result.value.then(data => {
    return data.json();
}).then(data => {
    g.next(data);
});

Generator中遇到yield的地方会进行暂停,所以我们需要手动调用next方法往下,next返回值的 value 属性便是我们需要的数据,这里是fetch方法返回的Promise对象,所以我们需要使用then回调,最后再调用g.next(data)结束并输出数据。

Generator 函数的缺点在于,我们每一次执行yield语句都需要手动进行next,不是很方便。

4. co

为了解决上方Generator函数需手动执行next方法的问题,TJ Holowaychuk大神编写了一个co函数库,能够使Generator 函数可以自动执行,比如原来我们需要这样:

let files = function* (){
    var f1 = yield readFile('/xxx/xxx'); // 读取file1文件
    var f2 = yield readFile('/xxx/xxx'); // 读取file2文件
        
    console.log(f1.toString());
    console.log(f2.toString());
};
        
        
files.next(); // 执行yield
files.next(); // 执行yield

使用co后:

var co = require('co');

co(files);

co 函数返回一个 Promise 对象,因此可以用 then 方法添加回调函数。

co(files).then(() => {
    console.log('执行完成');
});

最后我们可以看到我们没有手动执行next方法,也会打印出所读取的文件。

co模块虽然很好的帮助了我们解决了Generator函数必须靠执行器的问题,但是使用起来我们都需要额外引入一个模块,那么有没有更加方便的方式来解决呢?继续往下看。

5. async and await

除了以上4中方式可以解决Javascript异步编程的问题外,ES7还提供了更加方便的async 函数和await命令,了解一下?

其实async是 Generator 函数的语法糖,不同点在于其内置了执行器,也就是说async函数自带执行器。看一下下面的例子:

let p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(1);
    }, 1000);
 });
    
let p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(2); 
    }, 1000);
});

async function waitFn() {
    let a = await p1; // await命令后面可以是 Promise 对象和原始类型的值,如果使原始类型最终也会返回为Promise对象
    let b = await p2;
 
    return a + b
}

        
// async函数的返回值是 Promise 对象, 可以用then方法指定下一步的操作
waitFn().then(result => {
    console.log(result);  // 2s后输出3
});

async函数内部return语句返回的值,会成为then方法回调函数的参数。因此这就像极了利用co包裹起来的Generator函数,只是把*替换成了async,把yield替换成了await。

可以说async and await 是ES7中最重要的一个特性,虽然其也存在一些弊端,但是相比较而言用其处理异步代码来说还是比较得心应手的。

结语

本文简单介绍了处理好Javascript异步代码的五种常见方式,每一种方式都有其使用和存在的条件和必要性,有兴趣的同学可以对其进行单独的拓展和探究,只有了解并掌握每一种方式各自的优点并加以运用,才能享受异步编程带来的快感。

YOLOv8与UNetV2融合:一种面向目标检测与图像分割的混合方法【附核心代码】 我们提出了一种基于YOLOv8和UNetV2相结合的混合架构。该架构利用YOLOv8作为主干进行目标检测,同时在YOLOv8的特征提取过程中,引入UNetV2来进行图像分割任务的增强。在该架构中,YOLOv8负责大范围目标检测和位置预测,而UNetV2则在检测网络的特征图基础上,通过其高效的上下文信息提取和细节恢复能力,进一步优化分割任务。在本文中,我们提出了一种改进YOLOv8的方法,通过引入图像分割网络UNetV2来提高图像分割检测性能。 阅读详情

相关推荐

告别单一查询!MultiQueryRetriever在LangChain中的高级用法解析

本文深入解析了LangChain中的MultiQueryRetriever高级用法,该工具通过大语言模型自动生成多样化查询,显著提升文档检索的召回率和准确性。文章详细介绍了其核心机制、高级配置调优策略以及在多语言和专业领域中的实际应用,为开发者提供了优化知识库问答系统的实用方案。

weixin_28730927的博客 271

关于JS下大批量异步任务按顺序执行解决方案一点思考

前言 最近需要做一个浏览器的, 支持大体积文件上传且要支持断点续传的上传组件, 本来以为很容易的事情, 结果碰到了一个有意思的问题: 循环执行连续的异步任务, 且后一个任务需要等待前一个任务的执行状态 这么说可能有点空泛, 以我做的组件举例: 这个组件本意是为了上传大体积视频, 和支持断点续传, 因为动辄几个G的视频不可能直接把文件读进内存, 只能分片发送(考虑到实际网络状态, 每次发送大小定在了...

weixin_33743880的博客 1975

VMware VSAN 高级参数介绍(测试用)

VSAN 的策略驱动让我们看到了VSAN无穷的潜力,其设计思路相当新颖,在一个基础资源池上使用策略就能实现不同对象的区分服务,而目前没有其他厂家能到VMware这样的高度。 VSAN 呈现给用户配置很简单,但实际上设计及后台比较复杂。笔者无意间发现了VSAN的隐藏高级参数设置,有很多好玩的选项想分享出来。这些参数全部是针对每主机进行设置的。VSAN 中有很多默认设置,这些设置应该都是研发人员多次测试得出的最优值,修改可能导致环境异常,并不建议修改! 目录 参数1:全闪配置下 SSD 写缓存最大.

山水牧羊 2030

项目优化(异步化)

任务:先修改图表任务状态为"执行中"。给chart表新增任务状态字段(比如排队中、执行中、已完成、失败),任务执行信息字段(用于记录任务执行中、或者失败的一些信息)通过保存到数据库中的记录来看到提交失败的任务,并且在程序空闲的时候,可以把任务从数据库中回调到程序里,再次去执行此任务。如果我们要执行的任务非常复杂,包含很多环节,在每一个小任务完成时,要在程序(数据库中)记录一下任务的执行状态(进度)。(此时在核心线程数、最大线程数以及任务队列中都占满了,以及无法接收新的任务了,所以说只能拒绝任务7)

weixin_52154534的博客 1175

格拉姆角场实战:东南大学轴承故障诊断数据集深度剖析与代码实现

本文深入剖析了东南大学轴承故障诊断数据集,并提供了完整的格拉姆角场实战应用指南。通过将一维振动信号转换为二维图像,结合卷积神经网络,构建了端到端的故障诊断流程。文章详细解读了数据集的工况、通道含义与故障类型,并附有可运行的代码实现,为工业设备智能运维提供了有效解决方案。

night的博客 508

EverOS:为AI智能体构建长期记忆系统的完整指南

长期记忆是AI智能体实现持续学习和自我演进的核心能力,它通过结构化存储和关联检索历史交互信息,使智能体能够跨越单次对话的局限。其技术原理通常涉及向量数据库、记忆提取算法和知识图谱等组件,用于对非结构化对话内容进行编码、组织和索引。这一能力的技术价值在于显著提升了智能体的个性化服务水平、任务完成连贯性以及从经验中学习的能力,是实现真正“智能”伙伴的关键。在应用场景上,长期记忆系统广泛应用于个性化聊天伴侣、持续学习的编程助手、游戏NPC角色塑造以及客户服务机器人等领域。本文以EverOS为例,深入解析了其提供的

weixin_28679635的博客 449

异步编程中的性能优化技巧

​ 异步编程是处理I/O密集型任务的利器,它可以大幅提高程序的响应速度和资源利用率。通过本文的介绍,我们学习了在异步编程中进行性能优化的几种方法,希望这些技巧能帮助你在实际项目中编写出高效、稳定的异步代码!今天,我们将深入探讨异步编程中的性能优化技巧,帮助你进一步提升异步代码的效率。如果你对计算机相关技术有更多的兴趣,想要持续的探索,请关注我的公众号哟!应尽量避免使用阻塞的I/O操作,改用异步I/O操作。:将多个小任务合并为一个较大的任务,减少切换的频率;:不当的阻塞操作会影响异步代码的效率;

Asunqingwen的博客 966

prplOS介绍

介绍prplOS是什么,特性、框架、编译等。

四儿家的小祖宗的博客 2119

Python异步生成器性能优化终极指南

Python异步生成器性能优化终极指南

专注分享技术、实用优质教程、资源 743

喷涂机器人系列编程:ABB IRB 5500_(7).喷涂质量控制与优化

通过编程手段对ABB IRB 5500喷涂机器人进行质量控制和优化,可以显著提高喷涂的均匀性和附着力,减少涂层缺陷。具体的方法包括喷涂参数的调整、路径规划的优化、喷涂效果的检测与反馈,以及喷涂参数的动态调整。综合评估系统可以进一步确保喷涂质量的稳定性和一致性,帮助汽车制造企业提高产品质量和生产效率。

zhubeibei168的博客 851

【图像拼接(Image Stitching)】关于【图像拼接论文精读】专栏的相关说明,包含专栏使用方法、阅读顺序、创新思路、文章汇总、源码汇总、数据集汇总等。总之,【图像拼接论文相关】看这一篇就够了

为什么会有这篇文章?因为专栏简介里写不下太多东西,只能通过这篇文章和大家交流,算是一个专栏阅读指南吧。说点心里话本来吧,我只想用优快云来记录自己学习【图像拼接】领域论文的过程,对每篇文章有个细致的理解,方便自己反复查阅。设置为付费也是因为涉及论文和本人其他项目需要,防止查重和其他问题,所以价格最开始设置的是专栏付费价格里最高的。起初,确实没有人看,一切也都平淡地度过着。

主要更新底层视觉(去噪、超分等)相关的科研内容,形式为【论文精读】+【论文复现】 4万+

AMD端侧大模型部署实战:路线选择、显存测算与HIP编译避坑

端侧大模型推理的核心,是在有限显存和本地算力约束下,把权重、KV Cache与运行时开销纳入同一套预算。其原理并不复杂:后端决定GPU/NPU执行路径,量化决定权重体积,KV Cache量化与Flash Attention决定长上下文可用性,prefill与decode则分别受算力和带宽制约。把这些概念理清,技术价值会体现在更低部署门槛、更稳长上下文吞吐和可复现的本地服务化能力上。典型场景包括本地长文档分析、私有化对话、代码辅助及常驻轻量任务。落到AMD平台,路线选择往往比参数调优更先决:ROCm+HIP、

weixin_34252686的博客 381

【推荐系统】推荐算法:冷启动-召回-粗排-精排-重排 解读

【推荐系统】推荐算法:冷启动-召回-粗排-精排-重排 解读

Danger的博客 3760

14个 JavaScript 代码优化技巧

点击上方“逆锋起笔”,公众号回复PDF领取大佬们推荐的学习资料作者 | Mahdhi Rezvi译者 | 王强策划 | 李俊辰这篇文章列举了一些技巧,可帮助你写出更好的 JavaScr...

code小生 310

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

JavaScript 性能优化实战:从代码优化到运行时效率提升指南

本文系统介绍了JavaScript性能优化的关键策略,涵盖代码优化、DOM操作、异步处理和运行时监控四大方面。在代码层面,建议减少全局变量、合理选择数据结构、优化循环逻辑;DOM操作方面强调批量处理、减少重排重绘;异步处理推荐使用requestAnimationFrame和WebWorker;内存管理则需注意及时清理监听器和定时器。文章还提供了列表渲染的优化案例,并给出性能检查清单,帮助开发者系统性地提升JavaScript执行效率,最终实现更流畅的用户体验。

jingpide9527的博客 919

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

带你了解JavaScript的异步

目录一、异步的由来二、异步模型解析1. 宏任务和微任务 一、异步的由来 异步编程常见于如JavaScript一类的单线程语言,用于解决由单线程导致的执行效率低下的问题。 单线程语言是相对于多线程语言(如java)而言的。多线程语言具备同时利用CPU的多个内核并行执行程序的能力,代码执行效率较高。多线程语言通常采用同步编程模型,即任何一个任务都必须等待它的上一个任务执行完毕后才可以执行,这种编程模型更方便组织代码逻辑和划分线程任务。 而单线程语言则无法利用CPU的多核优势,它的主线程在同一时间只能执行一个任务

夕山雨的博客 1920

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Benchmark.js测试性能调优:基于测试结果的代码优化策略

Benchmark.js是一个强大的JavaScript性能测试库,能够提供高精度计时器并返回具有统计意义的测试结果。这个库被广泛应用于jsPerf.com等平台,帮助开发者准确测量代码性能。本文将详细介绍如何利用Benchmark.js的测试结果进行代码优化,提升应用性能。 ## 🔍 为什么需要性能测试? 在开发过程中,我们经常会遇到这样的问题:两种实现方式哪个更快?某个优化是否真的有效?

gitblog_00345的博客 412

JS异步开发总结

1 前言 众所周知,JS语言是单线程的。在实际开发过程中都会面临一个问题,就是同步操作会阻塞整个页面乃至整个浏览器的运行,只有在同步操作完成之后才能继续进行其他处理,这种同步等待的用户体验极差。所以JS中引入了异步编程,主要特点就是不阻塞主线程的继续执行,用户直观感受就是页面不会卡住。 2 概念说明 2-1 浏览器的进程和线程 首先可以确定一点是浏览器是多进程的,比如打开多个窗口可能就对应着多个进...

weixin_34379433的博客 168

14 个 JavaScript 代码优化建议

14 个 JavaScript 代码优化建议 1. 删除不使用的代码和功能 程序包含越多的代码,给客户端传递的数据就越多。浏览器也需要更多的时间去解析和编译代码。 有时,代码里也许会包含完全未使用到的功能,最好只将这些额外的代码保留在开发环境中,并且不要把它们留到生产环境中,因为无用的代码可能会增加客户端浏览器的负担。 经常问自己那个函数、特性或代码是否是必需的。 你可以手动的删掉无用的代码,也可以用工具 Uglify 或 谷歌开发的 Closure Compiler 帮你删。你甚至可以使用一种叫做 tr

ʚ菲菲的博客ɞ 396

5 个 JavaScript 代码优化技巧

整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。

郊眠寺 459

5 个JavaScript代码优化技巧

通过收集这些编码小技巧,提高编写优雅且可维护代码的能力。作者:天行无忌链接:https://juejin.cn/post/7194393614175666237来源:稀土掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

fury的博客 705

javascript代码_JavaScript的异步代码优化

前言在实际编码中,我们经常会遇到Javascript代码异步执行的场景,比如ajax的调用、定时器的使用等,在这样的场景下也经常会出现这样那样匪夷所思的bug或者糟糕的代码片段,那么处理好你的Javascript异步代码成为了异步编程至关重要的前提。下面我们从问题出发,一步步完善你的异步代码。异步问题1. 回调地狱首先,我们来看下异步编程中最常见的一种问题,便是回调地狱。它的出现是由于异步代码执行...

weixin_39888807的博客 94

js异步处理的三种方式

js异步处理的三种方式 写在前面  javascript语言的执行环境是"单线程"(single thread),就是指一次只能完成一件任务。如果有多个任务,就必须排队,等前面一个任务完成,再执行后面一个任务,以此类推。  这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。 单线程 function f1() { console.log('1') } function f2() { console.

高先生的猫 1410
上一篇: 谈谈前端异常捕获与上报
下一篇: 新书发售 | Vue 项目构建与开发入门
劳卜
博客等级 码龄10年 5粉丝 23原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值