【JavaScript 漫游】【017】异步操作概述

雪山
文章简介

本文为【JavaScript 漫游】专栏的第 017 篇文章,主要记录了 ES5 规范中异步操作的基本知识点。

  1. 单线程模型
  2. 同步任务和异步任务
  3. 任务队列和事件循环
  4. 异步操作的模式

单线程模型

单线程模型指的是,JS 只在一个线程上运行。它同时只能执行一个任务,其他任务都必须在后面排队等待。

JS 之所以采用单线程模型,是不想让浏览器变得太复杂。多线程需要共享资源、且有可能修改彼此的运行结果,对于一种网页脚本语言来说过于复杂。

采用该模型的好处是实现起来比较简单,执行环境相对单纯。而坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。

常见的浏览器无响应,往往就是因为某一段 JS 代码长时间运行,导致整个页面卡在这个地方,其他任务无法执行。JS 语言本身并不慢,慢的是读写外部数据,比如等待 Ajax 请求返回结果。这个时候,如果对方服务器迟迟没有响应,或者网络不畅通,就会导致脚本的长时间停滞。

JS 采用了事件循环机制来解决上述问题。如果想要利用多核 CPU 的计算能力,HTML5 提出了 Web Worker 标准,允许 JS 脚本创建多个线程,分为主线程和其他子线程,子线程完全受主线程控制,且不得操作DOM。

总的来说,单线程模型虽然对 JS 构成了很大的限制,但也因此使它具备了其他语言不具备的优势。如果用得好,JS 程序是不会出现堵塞的。

同步任务与异步任务

程序里面所有的任务,可以分成两类:同步任务synchronous 和异步任务 asynchronous

同步任务是那些没有被引擎挂起、在主线程上排队执行的任务。只有前一个任务执行完毕,才能执行后一个任务。

异步任务是那些被引擎放在一边,不进入主线程、而进入任务队列的任务。只有引擎认为某个异步任务可以执行了(比如 Ajax 操作从服务器得到了结果),该任务(采用回调函数的形式)才会进入主线程执行。排在异步任务后面的代码,不用等待异步任务结束会马上运行,也就是说,异步任务不具有堵塞效应。

举例来说,Ajax 操作可以当作同步任务处理,也可以当作异步任务处理,由开发者决定。如果是同步任务,主线程就等着 Ajax 操作返回结果,再往下执行;如果是异步任务,主线程在发出 Ajax 请求以后,就直接往下执行,等到 Ajax 操作有了结果,主线程再执行对应的回调函数。

任务队列和事件循环

JS 运行时,除了一个正在运行的主线程,引擎还提供了一个任务队列(task queue),里面是各种需要当前程序处理的异步任务。(实际上,根据异步任务的类型,存在多个任务队列。为了方便理解,这里假设只存在一个队列。)

首先,主线程会去执行所有的同步任务。等到同步任务全部执行完,就会去看任务队列里面的异步任务。如果满足条件,那么异步任务就重新进入主线程开始执行,这时它就变成同步任务了。等到执行完,下一个异步任务再进入主线程开始执行。一旦任务队列清空,程序就结束执行。

异步任务的写法通常是回调函数。一旦异步任务重新进入主线程,就会执行对应的回调函数。如果一个异步任务没有回调函数,就不会进入任务队列,也就是说,不会重新进入主线程,因为没有用回调函数指定下一步的操作。

JavaScript 引擎怎么知道异步任务有没有结果,能不能进入主线程呢?答案就是引擎在不停地检查,一遍又一遍,只要同步任务执行完了,引擎就会去检查那些挂起来的异步任务,是不是可以进入主线程了。这种循环检查的机制,就叫做事件循环(Event Loop)。

异步操作的模式

回调函数

回调函数是异步操作最基本的方法。

下面是两个函数 f1f2,编程的意图是 f2 必须等到 f1 执行完成,才能执行。

function f1(callback) {// ...callback();
}function f2() {// ...
};f1(f2);

回调函数的优点是简单、容易理解和实现,缺点是不利于代码的阅读和维护,各个部分之间高度耦合,使得程序结构混乱、流程难以追踪(尤其是多个回调函数嵌套的情况),而且每个任务只能指定一个回调函数。

事件监听

另一种思路是采用事件驱动模式。异步任务的执行不取决于代码的顺序,而取决于某个事件是否发生。

还是以 f1f2 为例。首先,为 f1 绑定一个事件(这里采用的是 jQuery 的写法)。

f1.on('done', f2);

f1 发生 done 事件,就执行 f2。然后,对 f1 进行改写:

function f1(){setTimeout(function() {// ...f1.trigger('done');}, 1000);
};

f1.trigger('done') 表示,执行完成后,立即触发 done 事件,从而开始执行 f2

这种方法的优点是比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以去耦合(decoupling),有利于实现模块化。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。阅读代码的时候,很难看出主流程。

发布/订阅

事件完全可以理解成信号,如果存在一个信号中心,某个任务执行完成,就向信号中心发布一个信号,其他任务可以向信号中心订阅这个信号,从而知道什么时候自己可以开始执行。这就叫做发布/订阅模式publish-subscribe pattern),又叫观察者模式observer pattern)。

这个模式有多种实现,具体的实现可以在使用 vuereact 技术栈的时候再进行研究,这里不作记录。

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

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

相关文章

Mysql如何优化数据查询方案

mysql做读写分离 读写分离是提高mysql并发的首选方案。 Mysql主从复制的原理 mysql的主从复制依赖于binlog,也就是记录mysql上的所有变化并以二进制的形式保存在磁盘上,复制的过程就是将binlog中的数据从主库传输到从库上。 主从复制过程详细分为3个阶段…

每日OJ题_二叉树dfs②_力扣129. 求根节点到叶节点数字之和

目录 力扣129. 求根节点到叶节点数字之和 解析代码 力扣129. 求根节点到叶节点数字之和 129. 求根节点到叶节点数字之和 难度 中等 给你一个二叉树的根节点 root ,树中每个节点都存放有一个 0 到 9 之间的数字。 每条从根节点到叶节点的路径都代表一个数字&am…

基于Windows搭建ftp服务器

WinR搜索’服务器管理器’,配置–用户和组 创建用户和组,将用户添加到组里 按图示创建一个文件,右键属性–安全 将刚才创建的组添加到对象里,并赋予他读取和写入的权限 角色–添加角色 勾选web服务器IIS 搜索IIS–网站右键–添加FTP站点…

【软考中级备考笔记】计算机体系结构

计算机体系结构 2月19日 – 天气:阴转小雪 1. 冯诺依曼计算机体系结构 冯诺依曼将计算机分为了五大部分,分别是: 控制器:主要负责协调指令到执行运算器:负责算数和逻辑运算存储器:负责存储在指令执行过程…

全网最 2024 GitHub Copilot超详细免费激活教学-干货

全网最🔥 2024 GitHub Copilot免费超详细激活教学 尊重原创,编写不易 ,帮忙点赞关注一下~转载小伙伴请注明出处!谢谢 GitHub Copilot 概述 GitHub Copilot 是由 GitHub 和 OpenAI 合作开发的一款人工智能编程助手。它利用机器…

JS基础(语法结构变量数据类型运算符流程控制)

JS基础(语法结构/变量/数据类型/运算符/流程控制) 目录 JS基础(语法结构/变量/数据类型/运算符/流程控制)什么是js?注释语法语法结构引入方式【1】script标签内部直接书写js代码【2】script标签src属性引入外部js代码 JS基础数据类型变量与常量变量的定义常量的定义…

ONLYOFFICE 8.0:引领数字化办公新纪元

目录 前言 软件安装 软件启动 软件新版本特性 个人评价 总结 前言 在当今快节奏的数字化世界中,高效的办公软件已成为企业竞争力的关键因素。ONLYOFFICE,作为全球领先的办公解决方案提供商,始终致力于通过技术创新来优化用户体验。如今…

Java使用Redis实现消息队列

近期刷Java面试题刷到了“如何使用Redis实现消息队列”,解答如下: 一般使用 list 结构作为队列, rpush 生产消息, lpop 消费消息。当 lpop 没有消息的时候,要适当sleep 一会再重试。若不使用sleep,则可以用…

【力扣 - 二叉树的最大深度】

题目描述 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 提示&#xff1a; 树中节点的数量在 [0, 10^4] 区间内。 -100 < Node.val < 100方法一&#xff1a;深度优先搜索 思路与算法 如…

Rust中不可变变量与const有何区别?

Rust作者认为变量默认应该是immutable&#xff0c;即声明后不能被改变的变量。这一点是让跨语言学习者觉得很别扭&#xff0c;不过这一点小的改变带来了诸多好处&#xff0c;本节我们来学习Rust的变量。 什么是变量&#xff1f; 如果你初次学习编程语言&#xff0c;变量会是一…

使用go-llama.cpp 运行 yi-01-6b大模型,使用本地CPU运行,速度挺快的

1&#xff0c;视频地址 2&#xff0c;关于llama.cpp 项目 https://github.com/ggerganov/llama.cpp LaMA.cpp 项目是开发者 Georgi Gerganov 基于 Meta 释出的 LLaMA 模型&#xff08;简易 Python 代码示例&#xff09;手撸的纯 C/C 版本&#xff0c;用于模型推理。所谓推理…

手撕C语言习题

定义一个表示公交线路的结构体&#xff0c;要求有线路名称(例如 616)&#xff0c;起始站&#xff0c;终点站&#xff0c;里程等成员&#xff0c; 定义结构体数组&#xff0c;用来存储多条条公交线路信息&#xff0c;要求能够输出从指定起始站发车的所以公交线路信息。 2、定义…

【软考高项】【教材知识梳理】- 15 - 第15章 - 项目风险管理

一、基本问题 1&#xff1a;按照可预测性&#xff0c;风险分哪三类&#xff1f; &#xff08;1&#xff09;已知风险&#xff1a;如项目目标不明确&#xff0c; 过分乐观的进度计划&#xff0c; 设计或施工变更和材料价格波动等。&#xff08;2&#xff09;可预测风险&#xff…

NVIDIA Corporation 在 GitHub 的官方主页

NVIDIA Corporation 在 GitHub 的官方主页 References https://github.com/NVIDIA References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

力扣题目训练(17)

2024年2月10日力扣题目训练 2024年2月10日力扣题目训练551. 学生出勤记录 I557. 反转字符串中的单词 III559. N 叉树的最大深度241. 为运算表达式设计优先级260. 只出现一次的数字 III126. 单词接龙 II 2024年2月10日力扣题目训练 2024年2月10日第十七天编程训练&#xff0c;今…

Mysql Day06

sql优化 插入数据 大批量插入数据 主键顺序插入性能高于乱序插入 load data local infile /root/load_user_100w_sort.sql into table tb_user fields terminated by , lines terminated by \n ; 主键优化 这个黄色的都是一个一个Page 主键乱序插入之后会变成1-3-2&#x…

qt - 19种精美软件样式

qt - 19种精美软件样式 一、效果演示二、核心程序三、下载链接 一、效果演示 二、核心程序 #include "mainwindow.h"#include <QtAdvancedStylesheet.h> #include <QmlStyleUrlInterceptor.h>#include "ui_mainwindow.h" #include <QDir&g…

从零开始学习Netty - 学习笔记 - NIO基础 - ByteBuffer: 简介和基本操作

NIO基础 1.三大组件 1.1. Channel & Buffer Channel 在Java NIO&#xff08;New I/O&#xff09;中&#xff0c;“Channel”&#xff08;通道&#xff09;是一个重要的概念&#xff0c;用于在非阻塞I/O操作中进行数据的传输。Java NIO提供了一种更为灵活和高效的I/O处理方…

基于微信小程序的日语学习的系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

中台的介绍及讲解

什么是中台 公司在新的一年规划中提出了新的发展战略&#xff0c;我们老板听说最近中台的概念很火&#xff0c;让我们调研公司实习中台战略的可行性&#xff0c;于是乎最近一段时间被老板折腾得够呛。刚开始并不理解什么是中台… 因此&#xff0c;写篇博客先简单介绍下什么是中…