前言

“异步”的大规模流行是在 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. resttemplate 请求方式详解

    get 普通请求: restemplate.getForEntity(url,String.class).getBody(); get 导出请求: restemplate.getForEntity(u ...

  2. 「洛谷 P3834」「模板」可持久化线段树 题解报告

    题目描述 给定n个整数构成的序列,将对于指定的闭区间查询其区间内的第k小值. 输入输出格式 输入格式 第一行包含两个正整数n,m,分别表示序列的长度和查询的个数. 第二行包含n个整数,表示这个序列各项 ...

  3. 如何在Uniapp中访问CabloyJS后端API管理系统

    介绍 CabloyJS是一款免费开源的NodeJS全栈开发框架,采用前后端分离设计,具备开箱即用的后台管理系统 Cabloy-SDK是专门为Uniapp应用量身定制的前端SDK,用于便捷的访问Cabl ...

  4. swap函数模板

    在许多应用程序中,都有交换相同类型的两个变量内容的需要.例如,在对整数数组进行排序时,将需要一个函数来交换两个变量的值,如下所示: void swap(int &a, int &b) ...

  5. VmWare安装Centos8注意事项

    VmWare安装Centos8注意事项 1.需选择稍后安装操作系统 2.选择操作系统版本 3.修改虚拟机配置 4.配置完成点击开启虚拟机(注意要将鼠标放在屏幕中央,点击一下后才能使用上下键进行选择) ...

  6. PowerShell 定时刷新查看文件内容

    get-content .\1.txt -ReadCount 0 -Tail 5 -Wait

  7. SAP Web Dynpro - 个性化和配置

    根据业务需求,您可以实现许多标准应用程序,并且Web Dynpro应用程序的UI可以根据要求而有所不同. 应用配置 要配置Web Dynpro应用程序,首先要为单个Web Dynpro组件配置数据记录 ...

  8. 基于slate构建文档编辑器

    基于slate构建文档编辑器 slate.js是一个完全可定制的框架,用于构建富文本编辑器,在这里我们使用slate.js构建专注于文档编辑的富文本编辑器. 描述 Github | Editor DE ...

  9. 解决nginx反向代理Mixed Content和Blockable问题

    nginx配置https反向代理,按F12发现js等文件出现Mixed Content,Optionally-blockable 和 Blockable HTTPS 网页中加载的 HTTP 资源被称之 ...

  10. UiPath鼠标操作文本的介绍和使用

    一.鼠标(mouse)操作的介绍 模拟用户使用鼠标操作的一种行为,例如单击,双击,悬浮.根据作用对象的不同我们可以分为对元素的操作.对文本的操作和对图像的操作 二.鼠标对文本的操作在UiPath中的使 ...