JavaScript闭包深入剖析:性能剖析与优化技巧

一、引言

在 JavaScript 的奇妙世界里,闭包无疑是一个既强大又迷人的特性。它就像是一把万能钥匙,为开发者打开了实现各种高级功能的大门。从数据封装与保护,到函数的记忆化,再到模块化开发,闭包都发挥着举足轻重的作用。在实际开发中,我们常常利用闭包来创建私有变量和方法,避免全局变量的污染,提高代码的可维护性和安全性。例如,在一个大型的 Web 应用中,我们可以使用闭包来封装一些只在特定模块内部使用的变量和函数,使得外部代码无法直接访问和修改,从而保证了数据的完整性和一致性。

然而,就像任何强大的工具一样,闭包也并非完美无缺。随着应用程序的规模和复杂度不断增加,闭包的使用可能会带来一系列性能问题。例如,由于闭包会持有对外部作用域变量的引用,这些变量在闭包存在期间无法被垃圾回收机制回收,从而可能导致内存泄漏和内存占用过高的问题。此外,闭包的创建和使用也可能会带来一定的性能开销,特别是在频繁创建和销毁闭包的场景下,这种开销可能会对应用程序的性能产生显著的影响。

因此,深入了解 JavaScript 闭包的性能特性,并掌握有效的优化策略,对于编写高效、可靠的 JavaScript 代码至关重要。在本文中,我们将深入探讨闭包的性能表现,分析可能导致性能问题的原因,并提出一系列实用的优化策略,帮助开发者在充分利用闭包强大功能的同时,避免潜在的性能陷阱。

二、什么是 JavaScript 闭包

(一)闭包的定义

在 JavaScript 中,闭包是指函数和其周围状态(词法环境)的引用捆绑在一起形成的组合 。简单来说,当一个函数内部定义了另一个函数,并且内部函数访问了外部函数作用域中的变量时,就形成了闭包。闭包使得内部函数可以在外部函数执行完毕后,仍然访问和操作外部函数作用域中的变量。例如:

function outerFunction() {let outerVariable = '我是外部变量';function innerFunction() {console.log(outerVariable);}return innerFunction;
}
const myClosure = outerFunction();
myClosure(); // 输出: 我是外部变量

在这个例子中,innerFunctionouterFunction 的内部函数,它访问了外部函数的变量 outerVariable。当 outerFunction 执行完毕并返回 innerFunction 后,innerFunction 仍然可以访问 outerVariable,这就是闭包的体现。

(二)闭包的形成条件

函数嵌套:在一个函数内部定义另一个函数,这是闭包形成的基础结构。例如上述代码中,innerFunction 定义在 outerFunction 内部。

内部函数引用外部函数变量:内部函数必须引用外部函数作用域中的变量或参数。在上面的例子中,innerFunction 引用了 outerFunction 中的 outerVariable

外部函数返回内部函数:外部函数将内部函数作为返回值返回,使得内部函数可以在外部函数作用域之外被调用。这样,通过返回的内部函数,就可以访问和操作外部函数作用域中的变量,从而形成闭包 。

(三)闭包的作用

数据封装:闭包可以用于创建私有变量和方法,实现数据的封装。外部作用域无法直接访问闭包内的变量,只能通过闭包提供的接口来访问和修改,从而保证了数据的安全性和隐私性。例如:

function counter() {let count = 0;return {increment: function() {count++;return count;},getCount: function() {return count;}};
}
const myCounter = counter();
console.log(myCounter.increment()); // 输出: 1
console.log(myCounter.getCount()); // 输出: 1

在这个例子中,count 是一个私有变量,只能通过 incrementgetCount 方法来访问和修改,外部代码无法直接访问 count,实现了数据的封装。

2. 函数柯里化:闭包在函数柯里化中发挥着重要作用。函数柯里化是将一个多参数函数转换为一系列单参数函数的过程。通过闭包,可以将部分参数预先绑定,返回一个新的函数,该函数接收剩余的参数并执行相应的操作。例如:

function add(x) {return function(y) {return x + y;};
}const add5 = add(5);
console.log(add5(3)); // 输出: 8

在这个例子中,add 函数返回一个闭包,该闭包保存了 x 的值,并返回一个新的函数,该函数可以接收 y 参数并返回 x + y 的结果。

3. 事件处理:在事件处理程序中,闭包可以用于保存和访问外部作用域中的变量。当事件触发时,闭包中的函数会被调用,并且可以访问和修改外部作用域中的变量,从而实现对事件的处理和状态的维护。例如:

function setupButton() {let count = 0;const button = document.getElementById('myButton');button.addEventListener('click', function() {count++;console.log(`按钮被点击了 ${count} 次`);});
}setupButton();

在这个例子中,addEventListener 的回调函数是一个闭包,它可以访问和修改 setupButton 函数作用域中的 count 变量,从而实现对按钮点击次数的统计。

三、闭包的性能分析

(一)内存占用分析

闭包会导致内存占用增加,这是因为闭包会持有对外部作用域变量的引用,使得这些变量在闭包存在期间无法被垃圾回收机制回收。例如:

function outerFunction() {let largeArray = new Array(1000000).fill(1); // 创建一个包含100万个元素的数组function innerFunction() {return largeArray.reduce((acc, num) => acc + num, 0);}return innerFunction;
}const myClosure = outerFunction();
// 此时,即使outerFunction执行完毕,largeArray也不会被垃圾回收,因为myClosure持有对它的引用

在这个例子中,outerFunction 内部创建了一个包含 100 万个元素的数组 largeArrayinnerFunction 形成闭包并引用了 largeArray。当 outerFunction 执行完毕并返回 innerFunction 后,largeArray 仍然被 innerFunction 引用,无法被垃圾回收,从而导致内存占用增加。如果这种情况在程序中频繁出现,可能会导致内存耗尽,影响程序的正常运行。

(二)执行效率分析

闭包对函数执行效率也有一定的影响。由于闭包涉及到作用域链的查找,当访问闭包中的变量时,需要沿着作用域链逐级查找,这会带来一定的性能开销。特别是在循环、递归等频繁操作中,这种开销可能会更加明显。例如:

function outerFunction() {let counter = 0;function innerFunction() {counter++;return counter;}return innerFunction;
}const myClosure = outerFunction();
for (let i = 0; i < 1000000; i++) {myClosure();
}
// 在这个循环中,每次调用myClosure都需要查找作用域链来访问counter变量,会有一定的性能开销

在上述代码中,innerFunction 形成闭包,在循环中频繁调用 myClosure 时,每次都需要查找作用域链来访问 counter 变量,这会增加函数执行的时间。相比之下,如果 counter 是一个局部变量,直接访问它的效率会更高。

(三)性能问题案例分析

在实际开发中,闭包可能会在一些场景下引发性能问题。例如,在大规模数据处理中:

function dataProcessor() {let data = new Array(1000000).fill(1); // 模拟大规模数据function processData() {return data.map(num => num * 2);}return processData;
}const processor = dataProcessor();
// 每次调用processor时,都会对100万个数据进行处理,且data不会被回收,可能导致性能问题和内存占用过高

在这个例子中,processData 函数形成闭包,持有对 data 的引用。每次调用 processor 时,都会对 100 万个数据进行处理,而且由于闭包的存在,data 不会被垃圾回收,这可能会导致性能问题和内存占用过高。

再比如,在频繁的事件绑定中:

function setupEventListeners() {let elements = document.getElementsByTagName('button');for (let i = 0; i < elements.length; i++) {elements[i].addEventListener('click', function() {console.log('Button clicked:', i);});}
}
setupEventListeners();
// 这里每个事件处理函数都形成闭包,持有对i的引用,可能导致内存泄漏和性能下降

在这个例子中,为每个按钮添加的点击事件处理函数都形成了闭包,持有对 i 的引用。当按钮数量较多时,这些闭包可能会导致内存泄漏和性能下降。因为即使按钮被移除或不再使用,这些闭包仍然存在,占用内存空间 。

四、闭包的优化策略

(一)及时解除引用

在这里插入图片描述

当闭包不再使用时,手动将闭包变量设为null,以释放内存。这是因为闭包会持有对外部作用域变量的引用,如果不及时解除引用,这些变量将无法被垃圾回收机制回收,从而导致内存泄漏。例如:

function createClosure() {let data = new Array(1000000).fill(1);function innerFunction() {return data.reduce((acc, num) => acc + num, 0);}return innerFunction;
}let closure = createClosure();
// 使用闭包
let result = closure(); 
console.log(result); // 闭包不再使用,手动解除引用
closure = null; 

在这个例子中,当closure不再使用时,将其设为null,这样data就不再被引用,垃圾回收机制可以回收其占用的内存,避免了内存泄漏。

(二)减少闭包的创建

避免在循环或频繁调用的函数中创建闭包,因为每次创建闭包都会带来一定的内存开销和性能损耗。例如,在下面的代码中,每次循环都创建一个新的闭包,这会导致内存开销增加:

function setupEventListeners() {let elements = document.getElementsByTagName('button');for (let i = 0; i < elements.length; i++) {elements[i].addEventListener('click', function() {console.log('Button clicked:', i);});}
}

可以将闭包的创建移到循环外部,以减少闭包的创建次数:

function setupEventListeners() {let elements = document.getElementsByTagName('button');function clickHandler(index) {return function() {console.log('Button clicked:', index);};}for (let i = 0; i < elements.length; i++) {elements[i].addEventListener('click', clickHandler(i));}
}

在这个改进后的代码中,clickHandler函数只创建一次,然后通过调用它并传入不同的参数来生成不同的事件处理函数,这样就减少了闭包的创建次数,降低了内存开销。

(三)使用 WeakMap

WeakMap是一种特殊的映射类型,它的键是弱引用,即当键对象不再被其他地方引用时,垃圾回收机制可以回收键对象及其对应的值。在闭包中使用WeakMap可以帮助减少内存泄漏的风险。例如:

function createClosure() {let privateData = new WeakMap();function setData(key, value) {privateData.set(key, value);}function getData(key) {return privateData.get(key);}return {setData: setData,getData: getData};
}let closure = createClosure();
let key = {};
closure.setData(key, 'private value');
console.log(closure.getData(key)); // 输出: private value// 解除对key的引用,此时privateData中对应的值也可以被回收
key = null; 

在这个例子中,privateData使用WeakMap来存储数据,当key不再被引用时,WeakMap中的键值对也可以被垃圾回收机制回收,从而减少了内存泄漏的风险。

(四)优化闭包的结构

通过调整闭包内函数的逻辑结构,提升执行效率。例如,减少不必要的作用域链查找,将频繁访问的外部变量缓存到局部变量中。如下代码:

function outerFunction() {let largeObject = {prop1: 'value1',prop2: 'value2',// 更多属性...};function innerFunction() {// 每次访问largeObject.prop1都需要查找作用域链console.log(largeObject.prop1); }return innerFunction;
}

可以优化为:

function outerFunction() {let largeObject = {prop1: 'value1',prop2: 'value2',// 更多属性...};let cachedProp1 = largeObject.prop1;function innerFunction() {// 直接访问局部变量,减少作用域链查找console.log(cachedProp1); }return innerFunction;
}

在优化后的代码中,将largeObject.prop1缓存到局部变量cachedProp1中,这样在innerFunction中访问cachedProp1时,直接从局部作用域获取,避免了每次都查找作用域链,提高了执行效率 。

五、实际应用中的优化实践

在这里插入图片描述

(一)在 Web 开发中的优化

在 Web 开发中,闭包常用于实现各种交互效果和数据处理逻辑。以一个简单的前端页面交互为例,当我们需要为多个按钮添加点击事件,并且每个按钮的点击事件都需要访问和修改一个共享的计数器变量时,可能会这样写代码:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8">
</head><body><button id="btn1">按钮1</button><button id="btn2">按钮2</button><button id="btn3">按钮3</button><script>function setupButtons() {let count = 0;const buttons = document.querySelectorAll('button');for (let i = 0; i < buttons.length; i++) {buttons[i].addEventListener('click', function () {count++;console.log(`按钮被点击了 ${count} 次`);});}}setupButtons();</script>
</body></html>

在这个例子中,每个按钮的点击事件处理函数都形成了闭包,持有对count变量的引用。这样虽然实现了功能,但存在性能问题。当按钮数量较多时,这些闭包会占用较多内存,并且每次点击事件触发时,都需要查找作用域链来访问count变量,会有一定的性能开销。

为了优化性能,可以将闭包的创建移到循环外部,减少闭包的创建次数:

function getData() {let dataList = [];function sendRequest() {const xhr = new XMLHttpRequest();xhr.open('GET', 'data.json', true);xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {const newData = JSON.parse(xhr.responseText);dataList = dataList.concat(newData);console.log('新数据已添加到列表:', dataList);}};xhr.send();}return sendRequest;
}const request = getData();
request();

在这个例子中,sendRequest函数形成闭包,持有对dataList变量的引用。当多次调用request函数发送 AJAX 请求时,由于闭包的存在,dataList不会被垃圾回收,可能会导致内存占用过高。为了优化这个问题,可以在 AJAX 请求完成后,及时解除对不需要的变量的引用:

function getData() {let dataList = [];function sendRequest() {const xhr = new XMLHttpRequest();xhr.open('GET', 'data.json', true);xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {const newData = JSON.parse(xhr.responseText);dataList = dataList.concat(newData);console.log('新数据已添加到列表:', dataList);// 数据处理完成后,解除对dataList的引用(如果不再需要)dataList = null; }};xhr.send();}return sendRequest;
}const request = getData();
request();

通过在数据处理完成后将dataList设为null,可以及时释放内存,避免内存泄漏 。

(二)在 Node.js 开发中的优化

在 Node.js 服务器端开发中,闭包在异步操作中广泛应用。例如,在处理文件读取和写入操作时,经常会使用闭包来处理异步回调:

const fs = require('fs');function readAndProcessFile(filePath) {let data = '';const readStream = fs.createReadStream(filePath);readStream.on('data', function (chunk) {data += chunk;});readStream.on('end', function () {// 处理读取到的数据const processedData = data.toUpperCase();console.log('处理后的数据:', processedData);// 写入文件操作const writeStream = fs.createWriteStream('output.txt');writeStream.write(processedData);writeStream.end();});
}readAndProcessFile('input.txt');

在这个例子中,data变量被data事件和end事件的回调函数引用,形成闭包。虽然这种方式实现了文件的读取和处理,但如果在高并发场景下,大量的文件操作都采用这种方式,可能会导致内存占用过高。为了优化性能,可以将闭包内的逻辑进行拆分,减少不必要的内存占用:

const fs = require('fs');function readFile(filePath) {return new Promise((resolve, reject) => {let data = '';const readStream = fs.createReadStream(filePath);readStream.on('data', (chunk) => {data += chunk;});readStream.on('end', () => {resolve(data);});readStream.on('error', (err) => {reject(err);});});
}function processData(data) {return data.toUpperCase();
}function writeFile(filePath, data) {return new Promise((resolve, reject) => {const writeStream = fs.createWriteStream(filePath);writeStream.write(data);writeStream.end();writeStream.on('finish', () => {resolve();});writeStream.on('error', (err) => {reject(err);});});
}async function main() {try {const data = await readFile('input.txt');const processedData = processData(data);await writeFile('output.txt', processedData);console.log('文件处理完成');} catch (err) {console.error('处理文件时出错:', err);}
}main();

在优化后的代码中,将文件读取、数据处理和文件写入操作分别封装成独立的函数,并使用Promiseasync/await来处理异步操作。这样可以避免在一个闭包中处理过多的逻辑,减少内存占用,同时提高代码的可读性和可维护性。

此外,在 Node.js 中,还可以利用WeakMap来优化闭包中的内存管理。例如,在实现一个简单的缓存机制时:

const cache = new WeakMap();function expensiveCalculation(key, value) {if (cache.has(key)) {return cache.get(key);}// 模拟复杂计算const result = value * value;cache.set(key, result);return result;
}const key = {};
const value = 5;
console.log(expensiveCalculation(key, value));
// 当key不再被引用时,WeakMap中的缓存可以被垃圾回收

在这个例子中,使用WeakMap来存储缓存数据,当键对象(这里是key)不再被引用时,WeakMap中的键值对也可以被垃圾回收,从而减少了内存泄漏的风险,提高了内存使用效率 。

六、最后总结

在这里插入图片描述

JavaScript 闭包作为一个强大而灵活的特性,在为我们带来诸多便利的同时,也需要我们谨慎对待其性能问题。通过深入分析闭包的内存占用和执行效率,我们了解到闭包可能导致内存泄漏和性能下降的原因,如对外部变量的引用导致内存无法及时回收,以及作用域链查找带来的性能开销等。

为了优化闭包的性能,我们提出了一系列实用的策略,包括及时解除引用、减少闭包的创建、使用 WeakMap 以及优化闭包的结构等。在实际应用中,无论是 Web 开发还是 Node.js 开发,这些优化策略都能够有效地提升程序的性能和稳定性。

展望未来,随着 JavaScript 引擎的不断发展和优化,闭包的性能可能会得到进一步提升。例如,未来的引擎可能会更加智能地识别和处理闭包中的变量引用,自动进行内存回收和优化。同时,随着前端和后端技术的不断演进,闭包在新的应用场景和架构中的性能表现也将成为研究和优化的重点。作为开发者,我们需要持续关注相关技术的发展,不断探索和实践新的优化方法,以充分发挥闭包的优势,为用户带来更加高效、流畅的应用体验。

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

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

相关文章

蓝桥杯嵌入式赛道备考1 —— 基础GPIO实战

1. 点亮一个LED 蓝桥杯的板子资料的URL&#xff0c;笔者是从GitHub - JoyRiderJie/LanQiaoBei-QianRuShi拉去下来的。这个是Github仓库地址。 从应用层去玩一个开发板子&#xff0c;首先需要的是去尝试是点亮一个LED。让我们切换到手册《CT117E——产品手册》的第11页&#x…

浅析DNS污染及防范

DNS污染&#xff08;DNS Cache Poisoning&#xff09;是一种网络攻击手段&#xff0c;通过篡改DNS服务器的缓存数据&#xff0c;将域名解析结果指向错误的IP地址&#xff0c;从而误导用户访问恶意网站或无法访问目标网站。这种攻击利用了DNS协议的特性&#xff0c;例如“只认第…

AI编程:如何编写提示词

这是小卷对AI编程工具学习的第2篇文章&#xff0c;今天讲讲如何编写AI编程的提示词&#xff0c;并结合实际功能需求案例来进行开发 1.编写提示词的技巧 好的提示词应该是&#xff1a;目标清晰明确&#xff0c;具有针对性&#xff0c;能引导模型理解问题 下面是两条提示词的对…

linux asio网络编程理论及实现

最近在B站看了恋恋风辰大佬的asio网络编程&#xff0c;质量非常高。在本章中将对ASIO异步网络编程的整体及一些实现细节进行完整的梳理&#xff0c;用于复习与分享。大佬的博客&#xff1a;恋恋风辰官方博客 Preactor/Reactor模式 在网络编程中&#xff0c;通常根据事件处理的触…

【思维导图】并发编程

学习计划&#xff1a;将目前已经学的知识点串成一个思维导图。在往后的学习过程中&#xff0c;不断往思维导图里补充&#xff0c;形成自己整个知识体系。对于思维导图里的每个技术知识&#xff0c;自己用简洁的话概括出来&#xff0c; 训练自己的表达能力。 并发和并行的区别 并…

【B站保姆级视频教程:Jetson配置YOLOv11环境(四)cuda cudnn tensorrt配置】

Jetson配置YOLOv11环境&#xff08;4&#xff09;cuda cudnn tensorrt配置 文章目录 0. 简介1. cuda配置&#xff1a;添加cuda环境变量2. cudnn配置3. TensorRT Python环境配置3.1 系统自带Python环境中的TensorRT配置3.2 Conda 虚拟Python环境中的TensorRT配置 0. 简介 官方镜…

【深度分析】DeepSeek 遭暴力破解,攻击 IP 均来自美国,造成影响有多大?有哪些好的防御措施?

技术铁幕下的暗战&#xff1a;当算力博弈演变为代码战争 一场针对中国AI独角兽的全球首例国家级密码爆破&#xff0c;揭开了数字时代技术博弈的残酷真相。DeepSeek服务器日志中持续跳动的美国IP地址&#xff0c;不仅是网络攻击的地理坐标&#xff0c;更是技术霸权对新兴挑战者的…

如何在数据湖中有效治理和管理“数据沼泽”问题,提高数据的可发现性和利用率?

在数据湖中有效治理和管理“数据沼泽”问题&#xff0c;提高数据的可发现性和利用率&#xff0c;需要从多个方面入手&#xff0c;包括数据治理、元数据管理、数据质量控制、安全性保障以及生命周期管理等。以下是具体的策略和方法&#xff1a; 1. 构建强大的数据治理框架 数据…

【4Day创客实践入门教程】Day3 实战演练——桌面迷你番茄钟

Day3 实战演练——桌面迷你番茄钟 目录 Day3 实战演练——桌面迷你番茄钟1. 选择、准备元件、收集资料2. 硬件搭建3.编写代码 Day0 创想启程——课程与项目预览Day1 工具箱构建——开发环境的构建Day2 探秘微控制器——单片机与MicroPython初步Day3 实战演练——桌面迷你番茄钟…

Oracle Primavera P6自动进行进度计算

前言 在P6 Professional 有一个自动计划计算的选项&#xff0c;很多人不了解该设置如何使用&#xff0c;以及什么时候该启动这项配置。 详情 P6 Professional 默认为非自动进度计算。启用自动选项后&#xff0c;可以快速查看调度更改的效果。 ​ ​ 如图所示&#xff0c;当你…

DeepSeek-R1 论文解读 —— 强化学习大语言模型新时代来临?

近年来&#xff0c;人工智能&#xff08;AI&#xff09;领域发展迅猛&#xff0c;大语言模型&#xff08;LLMs&#xff09;为通用人工智能&#xff08;AGI&#xff09;的发展开辟了道路。OpenAI 的 o1 模型表现非凡&#xff0c;它引入的创新性推理时缩放技术显著提升了推理能力…

大模型GUI系列论文阅读 DAY4续:《Large Language Model Agent for Fake News Detection》

摘要 在当前的数字时代&#xff0c;在线平台上虚假信息的迅速传播对社会福祉、公众信任和民主进程构成了重大挑战&#xff0c;并影响着关键决策和公众舆论。为应对这些挑战&#xff0c;自动化假新闻检测机制的需求日益增长。 预训练的大型语言模型&#xff08;LLMs&#xff0…

LevelDB 源码阅读:写入键值的工程实现和优化细节

读、写键值是 KV 数据库中最重要的两个操作&#xff0c;LevelDB 中提供了一个 Put 接口&#xff0c;用于写入键值对。使用方法很简单&#xff1a; leveldb::Status status leveldb::DB::Open(options, "./db", &db); status db->Put(leveldb::WriteOptions…

【Proteus仿真】【51单片机】多功能计算器系统设计

目录 一、主要功能 二、使用步骤 三、硬件资源 四、软件设计 五、实验现象 联系作者 一、主要功能 1、LCD1602液晶显示 2、矩阵按键​ 3、加减乘除&#xff0c;开方运算 4、带符号运算 5、最大 999*999 二、使用步骤 基于51单片机多功能计算器 包含&#xff1a;程序&…

origin调整图像的坐标轴,修改坐标轴起始点,增量

接上一篇帖子&#xff0c;如果再修改数据之后或者当前的数据之间差距较小&#xff0c;怎么通过调整坐标轴来使数据之间的差距更明显&#xff0c;举个例子&#xff0c; 像下面这个图的entropy指标&#xff0c;都是介于6到9之间&#xff0c;如果y轴坐标都从0开始&#xff0c;使用…

Redis_Redission的入门案例、多主案例搭建、分布式锁进行加锁、解锁底层源码解析

目录 ①. Redis为什么选择单线程&#xff1f; ②. 既然单线程这么好,为什么逐渐又加入了多线程特性&#xff1f; ③. redis6的多线程和IO多路复用入门篇 ④. Redis6.0默认是否开启了多线程&#xff1f; ⑤. REDIS多线程引入总结 ①. Redis为什么选择单线程&#xff1f; ①…

ARM嵌入式学习--第十一天(中断处理 , ADC)

--中断的概念 中断是指计算机运行过程中&#xff0c;出现某些意外情况需主机干预时&#xff0c;机器能自动停止正在运行的程序并转入处理新情况的程序&#xff0c;处理完毕后又返回被暂停的程序继续运行 --CPU处理事情的方式 -轮询方式 不断查询是否有事情需要处理&#xff0c…

vue2项目(一)

项目介绍 电商前台项目 技术架构&#xff1a;vuewebpackvuexvue-routeraxiosless.. 封装通用组件登录注册token购物车支付项目性能优化 一、项目初始化 使用vue create projrct_vue2在命令行窗口创建项目 1.1、脚手架目录介绍 ├── node_modules:放置项目的依赖 ├──…

[ACTF2020 新生赛]BackupFile1

题目 翻译&#xff0c;尝试找出源文件&#xff01; 扫目录使用参数-e * python dirsearch.py -u http://0c3b21c0-d360-4baa-8b97-aa244f4c4825.node5.buuoj.cn:81/ -e * 最终扫描到一个文件名为&#xff1a;/index.php.bak的文件&#xff0c;把备份文件下载下来 源码 <?…

OPENPPP2 —— VMUX_NET 多路复用原理剖析

在阅读本文之前&#xff0c;必先了解以下几个概念&#xff1a; 1、MUX&#xff08;Multiplexer&#xff09;&#xff1a;合并多个信号到单一通道。 2、DEMUX&#xff08;Demultiplexer&#xff09;&#xff1a;从单一通道分离出多个信号。 3、单一通道&#xff0c;可汇聚多个…