乐闻世界logo
搜索文章和话题

前端面试题手册

ES6 中有哪些解决异步的方法?

在ES6(ECMAScript 2015)及之后的版本中,引入了多种解决异步编程问题的方法。这些方法提高了代码的可读性、易维护性,并使得异步逻辑的处理变得更加直观。下面是几种主要的异步处理方法:1. PromisesES6正式引入了Promise对象,这是处理异步操作的一种方法。一个Promise代表了一个异步操作的最终完成 (或失败) 及其结果值。Promise有三种状态:pending(等待中), fulfilled(已成功), 和 rejected(已失败)。示例:const myPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve('数据已获取'); }, 2000);});myPromise.then( (value) => { console.log(value); }, // 成功处理函数 (error) => { console.error(error); } // 失败处理函数);2. Generators虽然ES6的生成器(Generator)函数本身不是异步的,但它们可以用于控制异步调用的流程。生成器函数允许函数执行过程中暂停和恢复,这意味着可以在某个操作等待异步结果时“暂停”函数执行。示例:function* generatorFunction() { const result = yield myPromise; console.log(result);}// 使用生成器控制异步流程const iterator = generatorFunction();const prom = iterator.next().value; // 获取由yield语句返回的Promiseprom.then((response) => iterator.next(response));3. Async/Awaitasync/await是在ES7(ECMAScript 2017)中引入的,但它是基于ES6的Promise进一步发展的。这是一个通过更简洁的方式使用Promise的语法糖。任何一个标记为async的函数都会返回一个Promise。await关键字可以用来等待Promise的解决,并暂停函数的执行,直到Promise被解决或拒绝。示例:async function fetchData() { try { const response = await fetch('https://api.example.com/data'); // 等待Promise解决 const data = await response.json(); // 等待Promise解决 console.log(data); } catch (error) { console.error('请求失败:', error); }}fetchData();每一种方法都有它的用例和适用场景。Promise可以很好地解决单个或多个异步操作链的情况。当我们需要在异步操作中暂停和恢复函数执行时,Generator函数可以很好地帮助我们管理复杂的流程。而async/await提供了一种更加直观和简洁的方式去处理Promise,特别是在需要等待多个异步操作完成时,代码的可读性和可维护性大大提高。
阅读 27·2024年6月24日 16:43

weak-Set、weak-Map 和 Set、Map 之间的区别是什么?

WeakSet 和 WeakMap 是 JavaScript 中的集合类型,与 Set 和 Map 相似,但它们之间有一些重要的区别。以下分别是 WeakSet/WeakMap 与 Set/Map 之间的主要区别:WeakSet 与 Set 的区别:弱引用:WeakSet:只能包含对象的弱引用。这意味着如果没有其他引用指向对象,这些对象是可以被垃圾回收机制回收的。Set:可以包含任意值的强引用,包括原始值或对象引用。只要 Set 存在,其中的元素就不会被垃圾回收机制回收。元素类型限制:WeakSet:只能存储对象,不能存储原始数据类型(如字符串、数字、布尔值等)。Set:可以存储任意类型的值,无论是原始数据类型还是对象。可枚举性:WeakSet:不能被迭代,也没有提供方法来获取大小(即没有 size 属性)或者清空集合的方法。Set:可迭代,且有 size 属性可以获取集合的大小,也提供了 clear 方法来清空集合。使用场景:WeakSet:适合用于存储没有任何其他引用的对象集合,通常用于管理对象的生命周期,防止内存泄漏。Set:适合于需要存储唯一值的场景,特别是当需要迭代或者获取集合大小时。WeakMap 与 Map 的区别:弱引用键:WeakMap:只接受对象作为键,并且这些键是弱引用的。如果没有其他引用指向键对象,那么这些键值对可以被垃圾回收机制回收。Map:可以接受任意类型的值作为键,包括原始数据类型和对象,这些键是强引用的。键类型限制:WeakMap:键必须是对象,不能是原始数据类型。Map:键可以是任意类型的值,包括原始数据类型和对象。可枚举性:WeakMap:同样不能被迭代,没有 size 属性,也不能清空整个集合。Map:可迭代,有 size 属性,并提供了 clear 方法。使用场景:WeakMap:经常用于缓存或者存储对象与数据的关联,同时不影响对象的垃圾回收。Map:适用于需要明确地将键映射到值,并且需要键的枚举、大小统计或者清空映射。示例:假设我们正在开发一个应用程序,该应用程序需要跟踪一组 DOM 元素是否被点击。我们可以使用 WeakSet 来存储这些 DOM 元素,如下所示:let clickedElements = new WeakSet();document.addEventListener('click', event => { if (event.target.tagName === 'BUTTON') { clickedElements.add(event.target); // ...执行一些操作... }});// 由于 WeakSet 对象的特性,当 DOM 元素被移除并且没有其他引用时,它将自动从 WeakSet 中移除,防止内存泄漏在这个例子中,如果没有 WeakSet,而是使用 Set,那么即使 DOM 元素被移除,它们也不会从集合中删除,这可能会导致内存泄漏。
阅读 38·2024年6月24日 16:43

var、let、const 之间的区别是什么?

varvar 是 JavaScript 早期版本中使用的变量声明关键字,它有几个特点:函数作用域:var 声明的变量是按照函数作用域进行绑定的,如果在函数外部声明,它就具有全局作用域。变量提升(Hoisting):使用 var 声明的变量会被提升至其作用域的顶部,但是只提升声明不提升初始化。重复声明:用 var 声明的变量可以在同一作用域中被重新声明。console.log(foo); // 输出 undefined 而不是抛出错误,因为变量提升var foo = 5;function testVar() { var bar = "hello";}console.log(bar); // 抛出错误,因为 bar 是在函数内部声明的,外部无法访问var foo = "world"; // 这是允许的,foo 被重新声明letlet 是 ES6 (ECMAScript 2015) 引入的关键字,用于声明变量,并且它带来了几个改进:块作用域:let 声明的变量是按照块作用域(如 {} 内部)进行绑定的。没有变量提升:let 声明的变量不会提升,它们必须在声明之后才能被使用。不能重复声明:在同一作用域下不能重新声明同一个变量。console.log(foo); // 抛出错误,foo 没有被提升let foo = 5;if (true) { let bar = "hello";}console.log(bar); // 抛出错误,bar 在 if 语句的块作用域外无法访问let foo = "world"; // 抛出错误,foo 不能被重新声明constconst 同样是在 ES6 引入的,用于声明常量,具有以下特性:块作用域:与 let 相同,const 声明的变量也是块作用域。没有变量提升:同样,const 声明的变量在声明之前不能被访问。不能重复声明:不能在相同作用域下重新声明。必须初始化:使用 const 声明变量时必须立即初始化,并且之后不能修改。const foo = 5;foo = 10; // 抛出错误,因为 const 声明的变量不能被重新赋值if (true) { const bar = "hello";}console.log(bar); // 抛出错误,因为 bar 在 if 语句的块作用域外无法访问const foo; // 抛出错误,因为 const 声明的变量必须在声明时初始化总结来说,let 和 const 是对 var 的一个改进,提供了块作用域特性,并解决了变量提升和重复声明所带来的问题。在现代 JavaScript 编程中,推荐使用 let 和 const 来声明变量,以便代码更加清晰和安全。
阅读 25·2024年6月24日 16:43

koa.js 如何实现文件上传的断点续传?

Koa.js 是一个轻量级的 Node.js web 框架,用于构建快速的 web 应用和 API。要在 Koa.js 中实现文件上传的断点续传,我们需要使用额外的中间件和库来管理文件的分片上传和断点续传的逻辑。下面是实现这个功能的一般步骤:1. 选择合适的中间件和库使用 koa-body 或 koa-multer 中间件来处理文件上传。选择支持断点续传的库,如 tus-node-server 或是使用流来手动处理。2. 设置文件上传中间件const Koa = require('koa');const koaBody = require('koa-body');const app = new Koa();app.use(koaBody({ multipart: true, formidable: { // 设置临时文件夹,用于保存上传的文件 uploadDir: './uploads', keepExtensions: true, }}));3. 实现分片上传逻辑分片的处理可以通过前端上传时携带分片信息,并在后端进行相应的处理:app.use(async ctx => { if (ctx.url === '/upload' && ctx.method === 'POST') { // 获取上传文件 const file = ctx.request.files.file; const { name, path } = file; // 获取分片信息等其他元数据,比如分片索引、总分片数、文件标识符等 const { index, total, identifier } = ctx.request.body; // 根据文件标识符和分片索引生成分片的唯一存储路径 const chunkPath = `./uploads/${identifier}_${index}`; // 将上传的分片文件移动到分片存储路径 const fs = require('fs'); const readable = fs.createReadStream(path); const writable = fs.createWriteStream(chunkPath); readable.pipe(writable); // 确认分片上传成功后,可以删除原上传的临时文件 fs.unlink(path, (err) => { if (err) throw err; }); ctx.body = '分片上传成功'; }});4. 断点续传和文件重组逻辑保存文件分片信息,可以使用数据库或者文件系统。定期检查已上传的分片,提供断点续传的信息给前端。前端在上传前检查已上传的分片,只上传未完成的部分。全部分片上传完毕后,后端合并分片。// 假设有一个合并分片的方法async function mergeChunks(chunks, dest) { // 合并所有分片 // ...}app.use(async ctx => { if (ctx.url === '/merge' && ctx.method === 'POST') { const { identifier, total } = ctx.request.body; const chunks = []; for (let i = 0; i < total; i++) { chunks.push(`./uploads/${identifier}_${i}`); } // 调用合并分片的方法 await mergeChunks(chunks, `./uploads/${identifier}.final`); ctx.body = '文件上传和合并成功'; }});5. 处理异常和错误在整个上传、续传、合并的过程中,要对可能发生的异常和错误进行处理,确保系统的稳定性。6. 前端实现前端需要使用支持断点续传的库(如 tus-js-client)或自己实现相关逻辑,包括如何分片、如何处理续传以及如何在上传完成后提示用户。以上是在 Koa.js 中实现文件上传断点续传的大体步骤。实际的逻辑可能会更加复杂,包括如何确保并发上传时分片的正确性,如何处理网络异常等多种情况。
阅读 67·2024年6月24日 16:43

一个 dom 必须要操作几百次,该如何解决,如何优化?

当面临需要进行几百次 DOM 操作的情况时,这通常意味着性能可能会受到影响,因为频繁的 DOM 更新可能会导致页面的重绘和重排,从而降低用户体验。为了优化这种情况,我们可以采取以下措施:1. 使用文档片段(DocumentFragment)文档片段是一个轻量级的DOM节点,它可以作为其他DOM节点的临时容器。我们可以在内存中构建整个DOM结构,然后一次性将其附加到DOM树上。这样可以减少页面的重绘次数。例子:// 创建一个新的空白的文档片段let fragment = document.createDocumentFragment();// 循环添加DOM节点到文档片段中for (let i = 0; i < 300; i++) { let div = document.createElement('div'); div.textContent = `Item ${i}`; fragment.appendChild(div);}// 最后,一次性将文档片段添加到DOM中document.body.appendChild(fragment);2. 批量更新样式修改元素的样式时,尽量避免逐个修改,而是使用类名(class)来对元素进行样式的修改,或者使用cssText一次性修改多个样式属性。例子:// 不推荐:逐个修改element.style.color = 'blue';element.style.fontSize = '14px';element.style.margin = '10px';// 推荐:使用cssText或者类名element.className = 'new-style';// 或者element.style.cssText = 'color: blue; font-size: 14px; margin: 10px;';3. 使用requestAnimationFrame如果DOM操作涉及到动画或者与视觉有关的更新,可以使用requestAnimationFrame。这个API会将DOM操作排队,以便在浏览器的下一个重绘之前执行,从而帮助避免不必要的重绘。例子:function update() { // 执行DOM操作}// 在下次重绘之前调用update函数requestAnimationFrame(update);4. 虚拟DOM库虚拟DOM技术(如React的虚拟DOM)可以帮助减少不必要的DOM操作,它通过在JavaScript内存中与实际DOM同步的数据结构来比较DOM的变化,并只更新发生变化的部分。例子:class MyComponent extends React.Component { render() { return ( <div> {this.props.items.map(item => <div key={item.id}>{item.text}</div>)} </div> ); }}5. 优化选择器和避免布局抖动尽量使用高效的选择器,避免使用复杂的CSS选择器,因为它们会增加查询DOM的时间。避免频繁地读写DOM属性,如offsetHeight,这可能会导致布局抖动(layout thrashing),应该将读操作和写操作分开进行。结论优化DOM操作的关键是减少重绘和重排的次数,以及减少与DOM的直接交互次数。以上提到的方法都是为了实现这个目标。在实际的项目中,我们可能需要根据具体的情况选择合适的优化策略。
阅读 8·2024年6月24日 16:43

module.exports和exports的区别是什么?export和export default的区别是什么?

module.exports vs exports在 Node.js 中,module.exports 和 exports 都是用于导出模块中的变量或者函数,以便其他文件可以使用 require 方法来引入和使用。但是它们之间存在一些区别:module.exports:这是真正用于定义模块导出的对象。在模块中,可以通过对 module.exports 赋值来指定导出的内容。如果你需要导出单个值或者一个完整的对象,通常会使用 module.exports。例子:假设你有一个工具模块,想要导出一个类。javascriptclass Tool { // ...}module.exports = Tool;exports:exports 是 module.exports 的一个引用,Node.js 默认在每个模块的头部创建了 exports = module.exports。它通常用于导出多个对象或函数。但是,如果你给 exports 直接赋一个新值,它就不再指向 module.exports,这就可能导致模块导出一个空对象 {}。例子:假设你有一个工具模块,想要导出多个函数。javascriptexports.function1 = function() { // ...};exports.function2 = function() { // ...};如果设置了 module.exports,exports 对象会被忽略。因此,不应该同时使用 module.exports 和 exports 导出不同的东西,以避免混淆或错误。export vs export default在 ES6 模块系统中,export 和 export default 用于导出模块内容,但它们的用途和语法有所不同:export:用于导出一个或多个命名的变量、函数、类等。导入时需要使用花括号 {} 并指定相应的名称。可以在一个模块中使用多个 export。例子:导出多个功能。javascriptexport const CONSTANT = 'constant value';export function myFunction() { // ...}export default:用于导出一个模块的默认输出。导入时不需要使用花括号,可以给导入的内容任意命名。一个模块只能有一个 export default。例子:导出一个模块的主要功能或类。javascriptexport default class MyClass { // ...}另一个例子是,在一个模块中即使用 export 导出多个值,也可以指定一个默认导出。javascriptexport const util1 = () => { /* ... */ };export const util2 = () => { /* ... */ };export default () => { /* ... */ }; // 这是默认导出在使用时,import myDefaultImport from 'my-module' 会导入 export default 的值,而 import { namedImport } from 'my-module' 会导入通过 export 命名导出的值。总结来说,module.exports 和 exports 用于 Node.js 的 CommonJS 模块系统,而 export 和 export default 用于 ES6 模块系统。选择哪一个取决于你的使用环境和特定的需求。
阅读 23·2024年6月24日 16:43

讲一下 import 的原理,与 require 有什么不同?

import 的原理在JavaScript中,import语句用于从模块中导入绑定(即函数、对象、原始类型等)。这是ES6规范(即ECMAScript 2015)引入的模块化特性的一部分。import的工作原理基于ECMAScript模块(ESM)系统。当你使用 import语句时,JavaScript引擎执行以下步骤:解析模块标识符:确定要导入的模块的位置及其文件路径。模块加载:如果模块尚未加载,JavaScript引擎会加载模块文件。编译模块:引擎会对模块代码进行编译,检查语法并进行优化。执行模块代码:在私有的模块作用域内执行模块代码,以初始化导出的绑定。缓存模块:模块的导出会被缓存,这意味着每个模块只会被执行一次,之后的导入会重用同一份导出的实例,保持状态的一致性。import 与 require 的不同import和 require都是JavaScript中用于加载模块的语句,但它们之间存在几个关键差异:语法规范:import是ES6中引入的模块化语法,而 require则来自于CommonJS规范,后者主要用于Node.js环境中。模块类型:import用于加载ESM模块,而 require用于加载CommonJS模块。加载方式:import声明是静态的,意味着它必须位于模块的顶部,不能动态运行或按条件导入模块。require是动态的,可以在代码的任何地方调用,支持条件加载和运行时动态计算路径。异步与同步:import可以支持异步模块的导入,通过 import()函数进行动态导入,返回一个Promise对象。require的加载是同步的,当调用 require时,代码会停止执行,直到模块被加载和返回。性能优化:由于 import是静态的,它允许JavaScript引擎进行更强大的性能优化,比如死代码消除和模块的静态分析。导出绑定的可变性:使用 import导入的绑定是活动的,也就是说如果导出的模块变量值发生变化,导入的绑定也会更新。使用 require导入的值是导出值的拷贝,一旦导入,无论源模块如何变化,导入的值都不会改变。例子使用 import:// ES6模块导入语法import { myFunction, myVariable } from './myModule.js';// 使用导入的函数和变量myFunction();console.log(myVariable);使用 require:// CommonJS模块导入语法const myModule = require('./myModule.js');// 使用模块的属性和方法myModule.myFunction();console.log(myModule.myVariable);在处理前端项目时,我们可能更倾向于使用 import,因为它与现代JavaScript模块化标准一致,而在Node.js环境中,尽管现在已经支持ESM,require依然被广泛使用,特别是在老项目中。
阅读 40·2024年6月24日 16:43

事件的触发过程是怎么样的?什么是事件代理?

事件的触发过程在Web开发中,事件的触发过程通常遵循以下几个步骤:捕获阶段:事件开始由最外层的document对象向事件目标节点传播的阶段。这个阶段不是所有事件都会有。目标阶段:事件到达目标元素,即实际触发事件的元素。冒泡阶段:事件从目标元素向外传播到document对象的阶段,事件可以在这个阶段的任意元素上被监听和处理。例如,假设我们有一个按钮(<button>元素),它位于一个段落(<p>元素)内,该段落又位于一个页面(document)。如果用户点击了按钮,那么在捕获阶段,事件会从document开始,经过<p>,直到达到<button>。此时,事件进入目标阶段,通常是在这里触发任何与按钮直接相关的事件监听器。之后,事件会进入冒泡阶段,途径<p>元素,最后到达document。在这个过程中,开发者可以选择在捕获阶段或冒泡阶段的任何点上处理事件。事件代理事件代理(Event Delegation)是一种常用的事件处理模式,它利用了JavaScript中事件的冒泡机制。在这种模式下,我们不是直接在目标元素(例如一个按钮)上设置事件监听器,而是在其父元素上设置一个事件监听器,监听其所有子元素的事件。当子元素上的事件被触发并冒泡到父元素时,父元素上的监听器会捕捉到这些事件,并根据事件的来源执行相应的事件处理函数。事件代理的优势在于:减少内存消耗:不需要为每个子元素都添加事件监听器,只需要在父元素上添加一个监听器即可。动态内容的事件管理:对于动态添加到页面中的元素,不需要重新绑定事件监听器,已有的事件代理依然有效。简化事件管理:通过在一个中心位置管理事件,使事件的添加、删除和修改变得更加容易。例子:假设我们有一个任务列表,每个任务项都有一个删除按钮,我们要给这些按钮添加点击事件来删除对应的任务项。如果使用事件代理,我们会在任务列表的容器上添加一个点击事件监听器:document.getElementById('taskList').addEventListener('click', function(event) { if (event.target.className === 'delete-btn') { // 如果点击的是删除按钮,则删除对应的任务项 event.target.closest('.task-item').remove(); }});在这个例子中,无论何时新增任务项,其删除按钮点击事件都会被容器上的事件监听器捕获和处理,而不需要单独给每个删除按钮绑定事件监听器。这就是事件代理的概念。
阅读 7·2024年6月24日 16:43

事件的触发过程是怎么样的?知道什么是事件代理吗?

事件的触发过程事件的触发过程,通常指的是在Web浏览器中,当用户与网页上的元素交互时(如点击按钮、移动鼠标等),将会触发相应的事件(如click, mousemove等)。此过程遵循一个特定的模式,称为“事件流”,它描述了从浏览器到DOM元素再回到浏览器的过程。事件流有两种模型:事件冒泡和事件捕获。事件捕获(Capturing): 事件开始于window对象,然后向下传递到目标元素的父元素,最终到达目标元素自身。这个过程是从外向内逐层捕获事件的过程。目标阶段(Targeting): 事件到达目标元素,执行绑定在该元素上的事件处理器。事件冒泡(Bubbling): 在目标阶段完成后,事件又会从目标元素开始,逐层向上冒泡,直到window对象。举个例子,假设我们有一个按钮元素,它位于一个表单内,该表单又位于HTML页面的body元素内。当用户点击按钮时,如果所有这些元素都对点击事件定义了处理函数:在捕获阶段:首先window对象检查是否有onclick事件处理器,然后是body元素,接着是form元素,最后是按钮本身。目标阶段:事件到达按钮元素,触发绑定在按钮上的点击事件处理器。在冒泡阶段:事件从按钮开始向上冒泡,先到form元素,然后是body元素,最后是window对象。开发者可以通过JavaScript控制事件监听器是在捕获阶段还是冒泡阶段触发。事件代理事件代理是一种常用于减少内存使用并避免为多个子元素绑定监听器的技术。事件代理的基本原理是利用了事件冒泡的特性。而不是在每个子元素上单独设置事件监听器,我们在其父元素上设置单个监听器,以监控所有子元素上的事件。在这个监听器中,我们可以使用 event.target属性来获取实际触发事件的元素,并据此执行相应的事件处理逻辑。事件代理的主要优势在于:内存效率:不必为每个子元素创建和维护独立的事件监听器,减少了内存的占用。动态元素:对于在运行时动态添加到DOM中的元素,我们不需要再单独为它们添加监听器,因为父元素上的代理监听器已经能够处理。简化管理:当有许多子元素需要相同的事件处理逻辑时,通过在父元素上设置单一监听器,简化了事件管理。举个例子,假设我们有一个待办事项列表(<ul>元素),它下面有多个列表项(<li>元素)。如果我们想要为每个列表项添加点击事件,使用事件代理的方式如下:// 假设ul元素有id="todo-list"var todoList = document.getElementById('todo-list');// 为ul元素添加点击事件监听器todoList.addEventListener('click', function(event) { if (event.target.tagName.toLowerCase() === 'li') { // 这里可以处理点击事件 console.log('你点击了列表项:' + event.target.textContent); }});
阅读 17·2024年6月24日 16:43

异步加载JS的方式有哪些?

在Web开发中,异步加载JavaScript是一种提高页面加载性能的常用技术,因为它允许网页在加载和解析JavaScript文件的同时,继续加载页面上的其他内容。以下是几种异步加载JavaScript的方法:1. 使用 async 属性HTML5提供了async属性,可以直接在<script>标签中使用。当浏览器遇到带有async属性的<script>标签时,它会继续加载网页的其他部分,同时异步加载脚本。一旦脚本下载完毕,它会被执行,但不会阻塞DOM的解析。<script async src="path/to/your-script.js"></script>例子:假设你有一个用于分析用户行为的脚本,这个脚本不需要在页面加载时立即执行,你就可以使用async属性来加载它。2. 使用 defer 属性与async类似,defer属性也可以在<script>标签中使用,以指示浏览器异步加载脚本。不同的是,使用defer属性的脚本会在整个文档解析完成后、DOMContentLoaded事件触发前执行。<script defer src="path/to/your-script.js"></script>例子:如果你的脚本需要访问DOM,但又不是紧急的,比如一个幻灯片效果,使用defer属性可以确保DOM加载完毕后再执行脚本。3. 动态创建 <script> 元素可以使用JavaScript动态创建一个<script>元素,并将其插入DOM中来异步加载脚本。var script = document.createElement('script');script.src = "path/to/your-script.js";script.async = true; // 可以设置为async或省略此行来异步加载document.head.appendChild(script);例子:在使用单页应用框架(如Angular或React)时,可能需要根据路由动态加载模块,此时可以动态创建<script>元素来加载需要的JavaScript文件。4. 使用 XMLHttpRequest 或 fetch API可以使用XMLHttpRequest或现代的fetch API来异步请求脚本内容,并在请求完成后使用eval()或者新的Function构造函数来执行代码。例子(使用fetch API):fetch('path/to/your-script.js') .then(response => response.text()) .then(text => eval(text)) .catch(error => console.log(error));需要注意的是,使用eval()或者Function构造函数来执行脚本会有安全风险,因为它们会执行任意的代码。因此,应该只从可信的源加载脚本,并尽量避免使用这些方法。5. 使用模块加载器使用模块加载器和打包工具(如Webpack、RequireJS等)可以帮助开发者更加有效地管理和异步加载模块。例子:在Webpack中,可以使用import()语法来实现代码分割和动态导入模块。import(/* webpackChunkName: "my-chunk-name" */ 'path/to/module').then(module => { // 使用模块});所有这些方法都可以减少页面首次加载时的时间,并且可以提供更好的用户体验。适当选择异步加载技术还能根据实际需求进行优化,例如,对于核心功能优先加载,对于非核心功能可以延后加载或按需加载。
阅读 5·2024年6月24日 16:43