前端面试题整理-前端异步编程

1. 进程、线程、协程的区别

在并发编程领域,进程、线程和协程是三个核心概念,它们在资源管理、调度和执行上有着本质的不同。

首先,进程是操作系统进行资源分配和调度的独立单位(资源分配基本单位),每个进程拥有自己的内存空间,这使得进程间相互隔离,从而提高了系统的稳定性。然而,这种隔离也带来了进程间通信的复杂性,需要通过特定的机制如管道、共享内存等来实现。进程的创建和销毁涉及到系统资源的分配和回收,因此开销相对较大。适用于需要高隔离性和独立资源的应用,比如浏览器的多进程架构,每个标签页运行在独立的进程中。

接着,线程作为进程的执行单元(CPU调度基本单位),共享进程的资源,包括内存空间,这使得线程间的通信更为简便。线程的创建和销毁开销相对较小,但仍然需要操作系统的调度,因此线程的并发执行能力受到操作系统调度策略和硬件资源的限制。适用于需要高效并发处理的场景,如Web服务器的请求处理、前端的异步操作(如Web Workers)。

最后,协程是一种更轻量级的并发机制,它允许程序在不同的执行点挂起和恢复,通常由程序内部进行调度,而不是依赖操作系统。协程特别适合处理I/O密集型任务,因为它们可以在等待I/O操作时挂起,从而提高资源利用率。协程的创建和销毁开销非常小,这使得它们在处理大量并发任务时非常有用,尤其是在Python、Go等语言中,协程被广泛用于提高并发性能。适用于需要大量并发但不需要多线程的场景,如JavaScript中的异步编程(Promise、async/await)、Python的异步I/O。

2. 说说他们的通信方式

进程、线程和协程之间的通信方式各有特点,下面分别介绍它们的通信机制:

(1) 进程通信(Inter-Process Communication, IPC)

  • 管道(Pipes):允许一个进程的输出成为另一个进程的输入。常用于父子进程间的单向或双向通信,简单且高效。
  • 命名管道(Named Pipes):类似于管道,但是它们在文件系统中有名字,可以跨会话使用。
  • 消息队列(Message Queues):允许进程以消息的形式交换数据,消息被存储在队列中直到被接收。支持异步通信,允许消息在进程间传递,适合复杂的消息传递场景。
  • 信号(Signals):一种由操作系统提供的异步通信机制,用于通知进程某个事件已经发生,适合简单的通知机制。
  • 共享内存(Shared Memory):允许两个或多个进程共享一个给定的存储区。速度最快的通信方式,进程共享一块内存区域,但需要同步机制来避免竞争条件。
  • 套接字(Sockets):支持不同主机之间的进程通信,可以是TCP/IP或UDP/IP协议。不仅用于网络通信,也可以用于本地进程间通信,灵活且强大。
  • 信号量(Semaphores)互斥锁(Mutexes):用于控制对共享资源的访问,防止多个进程同时访问同一资源。

(2) 线程间通信

  • 共享内存:由于线程共享相同的内存空间,它们可以直接通过读取和修改共享变量来通信,效率高。
  • 互斥锁(Mutexes):用于同步线程对共享资源的访问,防止数据竞争。
  • 条件变量(Condition Variables):允许线程在某个条件为真之前挂起,并在条件变为真时被唤醒。线程可以等待特定条件满足后继续执行,适合复杂的同步场景。
  • 信号量(Semaphores):用于控制对共享资源的访问,也可以用于线程间的同步,适合计数资源的同步。
  • 屏障(Barriers):同步机制,用于等待一定数量的线程都到达某个点后再继续执行。

(3) 协程间通信

  • 通道(Channels):在支持协程的语言中(如Go),通道是一种同步通信机制,允许协程通过发送和接收数据来通信,通常用于协程间的同步和数据交换。类似于管道,用于协程间传递消息或数据,直观且易于使用。
  • 共享变量:类似于线程,协程也可以通过共享变量来通信,但需要小心处理同步问题,以避免竞态条件。
  • 事件循环(Event Loop):在JavaScript中,协程(如通过async/await实现的异步函数)通常依赖于事件循环来管理异步操作,事件循环负责调度和执行异步任务。
  • Future/Promise:用于处理异步操作的结果,提供一种优雅的方式来处理协程间的结果传递。

3. js 是线程还是进程

在浏览器环境中,JavaScript 是单线程的。它在一个线程中执行代码,处理事件和更新用户界面。JavaScript 使用事件循环来管理异步操作。事件循环允许 JavaScript 处理异步任务,如网络请求或定时器,而不会阻塞主线程。虽然 JavaScript 本身是单线程的,但可以通过 Web Workers 创建多线程环境。Web Workers 允许在后台线程中运行代码,从而避免阻塞主线程。这种设计使得 JavaScript 能够高效地管理用户界面交互和后台任务。

4. js 事件循环机制

原理

JS是单线程的,为了防止代码阻塞,把任务分成同步任务和异步任务。
同步任务放入JS引擎直接执行,原地等待结果,其任务放入执行栈中按顺序执行;而异步任务需要放入宿主环境(浏览器、Node),不用原地等待结果,比较耗时,其任务放在任务队列中。
首先,执行栈中的同步任务会按顺序执行。当执行栈为空时,事件循环会检查任务队列。执行所有的微任务。如果调用栈为空,则从任务队列中取出一个宏任务并执行。执行完毕后,事件循环再次检查任务队列,重复这个过程。
在 JavaScript 中,任务可以分为同步任务、宏任务(Task),和微任务(Microtask)。以下是一些常见的例子:

同步任务

这些任务会立即执行,按顺序依次完成,不会被中断。

  • 普通的变量声明和赋值
  • 函数调用
  • console.log

宏任务(Task)

这些任务会被添加到任务队列中,等到主线程空闲时执行。

  • 整个脚本(初始执行)(指从头到尾执行一段 JavaScript 代码。它是事件循环中第一个被处理的宏任务)
  • setTimeout
  • setInterval
  • I/O 操作(读取文件或发送网络请求)
  • UI 渲染事件
  • setImmediate(Node.js)

微任务(Microtask)

这些任务会在当前宏任务执行结束后立即执行,在下一个宏任务开始前完成。

  • Promise 的回调函数(then, catch, finally
  • process.nextTick(Node.js)
  • MutationObserver
  • async/awaitawait之后的代码都看作微任务!(因为 await 会暂停函数的执行,并让出事件循环。在 await 的 Promise 解决后,函数会继续执行,后续代码作为微任务在当前宏任务完成后执行。)

执行顺序

  1. 执行同步任务。
  2. 当前宏任务执行完毕后,执行所有微任务。
  3. 执行下一个宏任务。

这种机制确保了同步任务优先执行,微任务在宏任务之间迅速处理,保持高效的异步操作。

举例

(1) 同步函数执行顺序

对于同步函数 f1()f2()

function f1(){
  for(let i=0; i<200; i++){}
}

function f2(){
  for(let i=0; i<300; i++){}
}

f1();
f2();

执行顺序是严格按照代码的顺序进行的:

  1. f1() 完成后才会执行 f2()
  2. 因为它们都是同步代码,所以没有异步调度的干扰。

(2) 异步函数执行顺序

对于异步函数 promise1()promise2()

async function promise1(){
  await xx;
  console.log(1);
}

async function promise2(){
  await xx;
  console.log(2);
}

promise1();
promise2();

假设 xx 是一个返回 Promise 的操作,执行顺序如下:

  1. promise1()promise2() 被调用,返回的 Promise 进入微任务队列。
  2. await xx 处,函数会暂停,控制权返回到事件循环。
  3. 一旦主线程的同步代码执行完毕,事件循环会处理微任务队列中的任务。
  4. await xx 完成后,console.log(1)console.log(2) 分别被放入微任务队列。
  5. 因为 promise1() 先调用,所以 console.log(1) 会先执行,接着是 console.log(2)

因此,输出结果是:

1
2
  • await 会暂停函数的执行,直到 Promise 解决为止。
  • async/await 使得异步代码看起来像同步代码,但实际执行顺序依赖于事件循环和微任务队列。
  • 微任务(例如 await 的处理)会在当前宏任务结束后立即执行。

(3) 混合任务

async function promise1() {
  console.log('A');
  await Promise.resolve(console.log('C'));
  console.log(1);
}

async function promise2() {
  console.log('B');
  await Promise.resolve(console.log('D'));
  console.log(2);
}

promise1();
promise2();

在这个代码片段中:
同步任务:

  • console.log('A')
  • console.log('C')
  • console.log('B')
  • console.log('D')
    这些会按照顺序立即执行。

微任务:

  • console.log(1)(作为 promise1 中的 await 后的代码)
  • console.log(2)(作为 promise2 中的 await 后的代码)
    这些会在当前宏任务完成后,作为微任务执行。

宏任务:

  • 每个 promise1()promise2() 的调用都是一个宏任务,但在这个上下文中,主要关注的是事件循环的执行顺序。

执行顺序:

  • 同步任务先执行,打印 ACBD
  • 然后执行微任务队列中的 console.log(1)console.log(2)

5. js 中的 async / defer 属性?平时用那种方式多?(参考掘金《「2021」高频前端面试题汇总之HTML篇》)

在这里插入图片描述
其中蓝色代表js脚本网络加载时间,红色代表js脚本执行时间,绿色代表html解析。

  • 没有deferasync 加载和执行都会阻塞html的解析

deferasync属性都是去异步加载外部的JS脚本文件,它们都不会阻塞页面的解析,区别:

  • defer 异步加载JS文件,不会立即执行,不阻塞html解析,会在解析完成后按顺序执行
  • async 异步加载和执行JS文件,不会阻塞html解析,下载完就执行,没有执行顺序

平时用那种方式多?
defer多。使用 defer 进行优化,不阻塞 html 解析;执行会按照顺序来,保证了正确性。

6. 说说异步编程中的 async / await

  • async: 用于定义一个异步函数,函数返回一个 Promise。即使没有显式返回 Promise,函数也会自动将返回值包装成一个 Promise
  • await: 用于暂停异步函数的执行,等待一个 Promise 完成,并返回其解析值。await 只能在 async 函数中使用。
    用法:
async function fetchData() {
  try {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error('Error:', error);
  }
}

工作原理:

  • 当函数被调用时,会立即返回一个 Promise
  • 函数内部遇到 await 时,会暂停执行,直到 Promise 解决或拒绝。
  • await 后的表达式会被转换为 Promise.resolve()

优势:

  • 简化代码: 使异步代码看起来更像同步代码,易于理解和维护。
  • 错误处理: 可以使用 try/catch 语句来处理异步操作中的错误。

注意事项:

  • await 只能在 async 函数中使用。
  • 多个 await 操作会导致顺序执行,可能影响性能。可以使用 Promise.all() 来并行执行多个异步操作。

示例对比:
Promise then/catch:

fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

Async/Await:

async function fetchData() {
  try {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error('Error:', error);
  }
}

结论:
async/await 是基于 Promise 的语法糖(在编程语言中,为了提高可读性和简洁性而提供的语法特性),使得异步代码更简洁和易读,是现代 JavaScript 开发中的重要工具。

7. await 会阻塞js线程加载执行吗

await 不会阻塞 JavaScript 线程的执行。它只是暂停当前异步函数的执行,等待 Promise 完成(被解决或拒绝)。在此期间,JavaScript 事件循环仍然可以处理其他任务,如用户交互、渲染等。

async function example() {
  console.log('Start');
  const result = await new Promise(resolve => setTimeout(() => resolve('Done'), 1000));
  console.log(result);
}

example();
console.log('This runs while waiting');

// 输出
Start
This runs while waiting
Done

8. 说说web worker

待看文章:一文彻底学会使用web worker

什么是 Web Worker

Web Worker 是一种在浏览器中创建后台线程的方法,用于执行复杂或耗时的 JavaScript 任务,而不会阻塞主线程。这有助于保持用户界面的流畅性。

为什么使用 Web Worker?

  1. 提高性能: 在处理密集计算任务时,Web Worker 可以防止页面卡顿。
  2. 增强用户体验: 通过避免长时间的 UI 阻塞,用户界面可以保持响应。

Web Worker 的使用场景

  • 复杂计算: 比如图像处理、数据分析、加密操作等。
  • 长时间运行任务: 如大数据处理、文件解析等。

示例

在一个项目中,我需要对用户上传的图片进行滤镜处理。由于处理过程较为复杂,我使用了 Web Worker 来避免阻塞主线程。

// worker.js
self.onmessage = function(event) {
  const imageData = event.data;
  // 进行复杂的图像处理
  const processedData = applyFilter(imageData);
  self.postMessage(processedData);
};

// 主线程
const worker = new Worker('worker.js');

worker.onmessage = function(event) {
  const processedData = event.data;
  // 显示处理后的图像
  displayImage(processedData);
};

worker.postMessage(originalImageData);

注意

  • 无法访问 DOM: Web Worker 不能直接操作 DOM。
  • 通信成本: 主线程和 Worker 之间通过消息传递进行通信,可能会有一定的延迟。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

动静态库:选择与应用的全方位指南

目录 1 软链接 1.1 软链接的建立方式和观察现象 1.2 软链接的原理 2 硬链接 2.1 硬链接的建立方式和观察现象 2.2 硬链接的本质 2.3 我们用户不能给目录建立硬链接 3. 动静态库复习 4 动静态库的制作 4.1 静态库的制作与使用 4.1.2 打包 4.1.3 静态库的使用 4.2 动…

【ROS2】多传感器融合、实现精准定位:robot_localization

1、简述 robot_localization在SLAM建图、导航中常用于将多个传感器融合(IMU、里程计、深度相机、GPS等),以提高定位精度,为机器人提供了在三维空间中的非线性状态估计 robot_localization包含两个状态估计节点: ekf_localization_node:扩展卡尔曼滤波(EKF),缺点是非…

极客大挑战2024wp

极客大挑战2024wp web 和misc 都没咋做出来&#xff0c;全靠pwn✌带飞 排名 密码学和re没做出几个&#xff0c;就不发了 web ez_pop 源代码 <?php Class SYC{public $starven;public function __call($name, $arguments){if(preg_match(/%|iconv|UCS|UTF|rot|quoted…

40分钟学 Go 语言高并发:并发下载器开发实战教程

并发下载器开发实战教程 一、系统设计概述 1.1 功能需求表 功能模块描述技术要点分片下载将大文件分成多个小块并发下载goroutine池、分片算法断点续传支持下载中断后继续下载文件指针定位、临时文件管理进度显示实时显示下载进度和速度进度计算、速度统计错误处理处理下载过…

李宏毅机器学习课程知识点摘要(1-5集)

前5集 过拟合&#xff1a; 参数太多&#xff0c;导致把数据集刻画的太完整。而一旦测试集和数据集的关联不大&#xff0c;那么预测效果还不如模糊一点的模型 所以找的数据集的量以及准确性也会影响 由于线性函数的拟合一般般&#xff0c;所以用一组函数去分段来拟合 sigmoi…

Spring Boot教程之五:在 IntelliJ IDEA 中运行第一个 Spring Boot 应用程序

在 IntelliJ IDEA 中运行第一个 Spring Boot 应用程序 IntelliJ IDEA 是一个用 Java 编写的集成开发环境 (IDE)。它用于开发计算机软件。此 IDE 由 Jetbrains 开发&#xff0c;提供 Apache 2 许可社区版和商业版。它是一种智能的上下文感知 IDE&#xff0c;可用于在各种应用程序…

本地Docker部署开源WAF雷池并实现异地远程登录管理界面

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

如何快速将Excel数据导入到SQL Server数据库

工作中&#xff0c;我们经常需要将Excel数据导入到数据库&#xff0c;但是对于数据库小白来说&#xff0c;这可能并非易事&#xff1b;对于数据库专家来说&#xff0c;这又可能非常繁琐。 这篇文章将介绍如何帮助您快速的将Excel数据导入到sql server数据库。 准备工作 这里&…

[产品管理-91]:产品经理的企业运营的全局思维-1

目录 前言&#xff1a;企业架构图 产品经理的企业运营全局思维 1、用户 - 用户价值与体验&#xff1a;真正的需求&#xff0c;真正的问题&#xff0c;一切的原点 2、大势 - 顺应宏观大势&#xff1a;政策趋势、行业趋势、技术趋势 3、市场 - 知己知彼&#xff1a;市场调研…

简单实现vue2响应式原理

vue2 在实现响应式时&#xff0c;是根据 object.defineProperty() 这个实现的&#xff0c;vue3 是通过 Proxy 对象实现&#xff0c;但是实现思路是差不多的&#xff0c;响应式其实就是让 函数和数据产生关联&#xff0c;在我们对数据进行修改的时候&#xff0c;可以执行相关的副…

论文解析:EdgeToll:基于区块链的异构公共共享收费系统(2019,IEEE INFOCOM 会议);layer2 应对:频繁小额交易,无交易费

目录 论文解析:EdgeToll:基于区块链的异构公共共享收费系统(2019,IEEE INFOCOM 会议) 核心内容概述 核心创新点原理与理论 layer2 应对:频繁小额交易,无交易费 论文解析:EdgeToll:基于区块链的异构公共共享收费系统(2019,IEEE INFOCOM 会议) 核心内容是介绍了一个…

基于python Django的boss直聘数据采集与分析预测系统,爬虫可以在线采集,实时动态显示爬取数据,预测基于技能匹配的预测模型

本系统是基于Python Django框架构建的“Boss直聘”数据采集与分析预测系统&#xff0c;旨在通过技能匹配的方式对招聘信息进行分析与预测&#xff0c;帮助求职者根据自身技能找到最合适的职位&#xff0c;同时为招聘方提供更精准的候选人推荐。系统的核心预测模型基于职位需求技…

SemiDrive E3 硬件设计系列---唤醒电路设计

一、前言 E3 系列芯片是芯驰半导体高功能安全的车规级 MCU&#xff0c;对于 MCU 的硬件设计部分&#xff0c;本系列将会分模块进行讲解&#xff0c;旨在介绍 E3 系列芯片在硬件设计方面的注意事项与经验&#xff0c;本文主要讲解 E3 硬件设计中唤醒电路部分的设计。 二、RTC 模…

Leetcode198. 打家劫舍(HOT100)

代码&#xff1a; class Solution { public:int rob(vector<int>& nums) {int n nums.size();vector<int> f(n 1), g(n 1);for (int i 1; i < n; i) {f[i] g[i - 1] nums[i - 1];g[i] max(f[i - 1], g[i - 1]);}return max(f[n], g[n]);} }; 这种求…

一文探究48V新型电气架构下的汽车连接器

【哔哥哔特导读】汽车电源架构不断升级趋势下&#xff0c;48V系统是否还有升级的必要&#xff1f;48V新型电气架构将给连接器带来什么改变&#xff1f; 在插混和纯电车型逐渐普及、800V高压平台持续升级的当下&#xff0c;48V技术还有市场吗? 这个问题很多企业的回答是不一定…

React学习05 - redux

文章目录 redux工作流程redux理解redux理解及三个核心概念redux核心apiredux异步编程react-redux组件间数据共享 纯函数redux调试工具项目打包 redux工作流程 redux理解 redux是一个专门用于状态管理的JS库&#xff0c;可以用在react, angular, vue 等项目中。在与react配合使…

2024年11月最新 Alfred 5 Powerpack (MACOS)下载

在现代数字化办公中&#xff0c;我们常常被繁杂的任务所包围&#xff0c;而时间的高效利用成为一项核心需求。Alfred 5 Powerpack 是一款专为 macOS 用户打造的高效工作流工具&#xff0c;以其强大的定制化功能和流畅的用户体验&#xff0c;成为众多效率爱好者的首选。 点击链…

batchnorm与layernorn的区别

1 原理 简单总结&#xff1a; batchnorn 和layernorm是在不同维度上对特征进行归一化处理。 batchnorm在batch这一维度上&#xff0c; 对一个batch内部所有样本&#xff0c; 在同一个特征通道上进行归一化。 举个例子&#xff0c; 假设输入的特征图尺寸为16x224x224x256&…

【c++丨STL】stack和queue的使用及模拟实现

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;C、STL 目录 前言 一、什么是容器适配器 二、stack的使用及模拟实现 1. stack的使用 empty size top push和pop swap 2. stack的模拟实现 三、queue的…

ApiChain 从迭代到项目 接口调试到文档生成单元测试一体化工具

项目地址&#xff1a;ApiChain 项目主页 ApiChain 简介 ApiChain 是一款类似 PostMan 的接口网络请求与文档生成软件&#xff0c;与 PostMan 不同的是&#xff0c;它基于 项目和迭代两个视角管理我们的接口文档&#xff0c;前端和测试更关注版本迭代中发生变更的接口编写代码…