前言

“异步”的大规模流行是在 Web 2.0浪潮中,它伴随着 AJAX 席卷了 Web。前端充斥了各种 AJAX 和事件,这些都是典型的异步应用场景。现在的 Web 应用已经不再是单台服务器就能胜任的时代了,在跨网络的架构下,异步已经是必不可少的标准配备了。

在浏览器中 JS 在单线程上执行,而它还与 UI 渲染共用一个线程。这意味着 JS 在执行的时候,UI 渲染和响应是处于停滞状态的。如果网页临时需要获取一个网络资源,通过同步的方式获取,JS 需要等待资源完成从服务器端获取后才能继续执行,这期间 UI 将停顿,不响应用户的交互行为。而采用异步请求,在请求资源期间,JS 和 UI 的执行都不会处于等待状态,可以继续响应用户的交互行为,给用户一个鲜活的页面。

何为异步

任务队列

对于长时间响应的任务,可以把它们放进另一个队列中,不影响其他任务的执行,这个队列就是任务队列。

存在于任务队列中的任务,又叫作异步任务。异步任务区别于同步任务,同步任务是在主线程中执行的,它通常来说不会消耗太多的时间去执行,所以放在主线程中非常合适。

事件循环

任务队列中的任务(异步任务)需要使用事件循环机制来执行。在进程启动时,就会有一个类似于 while 循环,没执行一次循环体的过程我们称为 Tick。每个 Tick 的过程就是查看是否有事件待处理,如果有,就取出时间及其相关的回调函数。如果存在关联的回调函数,就执行它们。然后进入下个循环,如果不再有事件处理,就退出进程。

宏任务和微任务

任务队列中的任务可以再细分为宏任务(Macrotask)和微任务(Microtask)。微任务的执行优先级比宏任务的优先级高。

Promise 是微任务,它优先于 setTimeout 宏任务。主线程先输出 “main task!!!”,然后执行微任务,控制台输出 “microtask!!!”,随后输出宏任务 “macrotask!!!”。

回调函数

向服务器请求数据也是异步事件,若我们要获取这个异步事件处理后的结果,需要使用回调函数来获取这个结果。通常,回调函数常常运用于异步事件中。

小明买茶

小明某一天在奶茶店购买一杯柠檬茶,小明心想,与其浪费时间等待,不如刷视频。

小明需要一直等待奶茶店将柠檬茶制作完成,然后将其递给他才算完成整个事件。在等待的过程中,他在刷视频。同一时间内,A 事件需要等待一段时间;B 事件在段时间内完成,这类情况就是异步任务

在时序图中,我们能很清楚地知道这些事件在一个时间段内应该处于什么位置。小明等待奶茶不应该影响他刷视频,整个体验会非常地友好。至于买的奶茶质量好与不好,不是我们关注的重点。

实际运用

以“小明买茶”故事为例,我们抽取一个函数。第一个参数是异步事件的名称,第二个参数异步事件执行的时间,第三个参数是回调函数作为参数传递。

为什么函数可以作为值进行参数传递,详细请看[JS]函数作为值

function doSomething(eventName, timeout, callback) {
console.log(`'${eventName}'正在进行中...`)
setTimeout(() => {
callback(`'${eventName}'事件已完成`) // 执行回调函数,提供一点信息。
}, timeout)
} // 异步事件
doSomething('小明购买奶茶', 3000, (info) => {
console.log(info)
doSomething('小明和朋友聊天', 1000, (info) => {
console.log(info)
})
}) // 同步事件
console.log('与此同时小明正在刷视频!')

异步事件处理完后,将结果传递给回调函数,所以 doSomething 函数是可以接收到回调函数传递过来的包含了结果的参数 info。

但是,在源代码中,回调函数中可以内嵌多个异步事件,这样层层嵌套在代码层面上会出现“倒金字塔”现象,不利于程序员后期的维护,这种现象叫作回调地狱

回调地狱

在“小明买茶”的案例中,回调内部再嵌套回调,其代码形状上看着像 180° 旋转之后的金字塔,这种层层嵌套就是回调地狱。

但是Promise可以解决回调地狱的问题。Promise 是一个对象,用于表示一个异步操作的最终完成(或失败)及其结果值。

function doSomething(eventName, timeout) {
console.log(`奶茶店接到'${eventName}'的订单,正在制作奶茶中...`)
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`'${eventName}'事件已完成`)
}, timeout)
})
} // 异步任务1
let promise01 = doSomething('小明购买奶茶', 3000).then((info) => {
console.log(info)
}) // 异步任务2
let promise02 = doSomething('小明和朋友聊天', 1000).then((info) => {
console.log(info)
}) // 同步任务
console.log('与此同时小明正在刷视频!')

使用 Promise 之后,解决了多层回调函数调用导致的“倒金字塔”现象。让我们看看实现效果:

JavaScript 异步编程(一):认识异步编程的更多相关文章

  1. C# 异步编程2 EAP 异步程序开发

    在前面一篇博文记录了C# APM异步编程的知识,今天再来分享一下EAP(基于事件的异步编程模式)异步编程的知识.后面会继续奉上TPL任务并行库的知识,喜欢的朋友请持续关注哦. EAP异步编程算是C#对 ...

  2. 多线程编程学习笔记——异步调用WCF服务

    接上文 多线程编程学习笔记——使用异步IO 接上文 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端 接上文 多线程编程学习笔记——异步操作数据库 本示例描述了如何创建一个WCF服务,并宿主 ...

  3. C#高级编程9-第13章 异步编程

    异步编程 1)异步编程的重要性 在C#5.0中提供了关键字:async和await 使用异步编程后台运行方法调用,程序的运行过程中就不会一直处于等待中.便于用户继续操作. 异步编程有3种模式:异步模式 ...

  4. php为什么需要异步编程?php异步编程的详解(附示例)

    本篇文章给大家带来的内容是关于php为什么需要异步编程?php异步编程的详解(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 我对 php 异步的知识还比较混乱,写这篇是为了 ...

  5. Java 异步编程 (5 种异步实现方式详解)

    ​ 同步操作如果遇到一个耗时的方法,需要阻塞等待,那么我们有没有办法解决呢?让它异步执行,下面我会详解异步及实现@mikechen 目录 什么是异步? 一.线程异步 二.Future异步 三.Comp ...

  6. 《Windows核心编程系列》十谈谈同步设备IO与异步设备IO之异步IO

    同步设备IO与异步设备IO之异步IO介绍 设备IO与cpu速度甚至是内存访问相比较都是比较慢的,而且更不可预测.虽然如此,通过使用异步设备IO我们仍然能够创造出更高效的程序. 同步IO时,发出IO请求 ...

  7. 《高性能javascript》 领悟随笔之-------DOM编程篇

    <高性能javascript> 领悟随笔之-------DOM编程篇一 序:在javaSctipt中,ECMASCRIPT规定了它的语法,BOM实现了页面与浏览器的交互,而DOM则承载着整 ...

  8. JavaScript 学习笔记之线程异步模型

    核心的javascript程序语言并没有包含任何的线程机制,客户端javascript程序也没有任何关于线程的定义,事件驱动模式下的javascript语言并不能实现同时执行,即不能同时执行两个及以上 ...

  9. 让你高效的理解JavaScript中的同步、异步和事件循环

    "同步请求","异步请求"相信这两词在程序猿的世界中频频出现,到底是词性的妖娆,还是撸代码的基础要求,下面直接分享本人学习的好东西,保证让你深入浅出,爽得不要不 ...

  10. 【转载】Javascript里面的线程和异步

    JavaScript引擎是单线程运行的,浏览器无论在什么时候都只且只有一个线程在运行JavaScript程序. 参考这篇文章 http://www.ruanyifeng.com/blog/2012/1 ...

随机推荐

  1. LC T668笔记 & 有关二分查找、第K小数、BFPRT算法

    LC T668笔记 [涉及知识:二分查找.第K小数.BFPRT算法] [以下内容仅为本人在做题学习中的所感所想,本人水平有限目前尚处学习阶段,如有错误及不妥之处还请各位大佬指正,请谅解,谢谢!] !! ...

  2. SQL Server 2019企业版和标准版的区别?

    来源公众号:SQL数据库运维 原文链接:https://mp.weixin.qq.com/s?__biz=MzI1NTQyNzg3MQ==&mid=2247485400&idx=1&a ...

  3. 【Azure 应用服务】NodeJS Express + MSAL 应用实现AAD集成登录并部署在App Service Linux环境中的实现步骤

    问题描述 实现部署NodeJS Express应用在App Service Linux环境中,并且使用Microsoft Authentication  Library(MSAL)来实现登录Azure ...

  4. CabloyJS - GitHub Readme

    简体中文 | English CabloyJS CabloyJS是一款顶级NodeJS全栈业务开发框架, 基于KoaJS + EggJS + VueJS + Framework7 文档 官网 & ...

  5. Redis初启(一)

    1.数据库存存储性能优化 在mysql的文章专题中我写过了关于传统关系型数据库的一些优化思路,整体来说,通过优化之后能够提升程序访问数据库的计算性能.但是还是有一些情况,即便是优化之后,使用传统关系型 ...

  6. 开发工具-Unix时间戳转换

    更新日志 2022年6月10日 初始化链接. https://toolb.cn/timestamp

  7. docker 操作 记录

    docker ps  #查看当前docker容器 docker exec -it  容器名称 sh  进入docker容器 docker stop 停止docker容器

  8. 从局部信息推测基恩士的Removing BackGround Information算法的实现。

    最近从一个朋友那里看到了一些基恩士的资料,本来是想看下那个比较有特色的浓淡补正滤波器的(因为名字叫Shading Correction Filter,翻译过来的意思有点搞笑),不过看到起相关文档的附近 ...

  9. 使用nodejs的wxmnode模块,开发一个微信自动监控提醒功能,做个天气预报。

    这个模块是一个公众号的模块,名字叫"帮你看着". 原本这个公众号是做股票监控提醒的,我也没炒股.因为接口支持写入任何内容,所以可以有其他的用处.比如做成天气预报定时提醒. 我们去n ...

  10. javaweb_Http学习

    1. 什么是HTTP? HTTP(超文本传输协议)是一个简单的请求-响应协议,它通常运行在TCP之上. 文本:html,字符串,~... 超文本:图片,音乐,视频,定位,地图..... 默认端口:80 ...