ES6进阶知识二

news2024/11/19 17:38:12

一、promise方法的案例

Promise对象通过new Promise()语法创建,它接受一个函数作为参数,该函数接受两个参数:resolve和reject。resolve表示异步操作成功,reject表示异步操作失败。

案例:异步加载图片

const loadImage = (url) => {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => {
      resolve(img);
    };
    img.onerror = () => {
      reject(new Error(`Failed to load image from ${url}`));
    };
    img.src = url;
  });
};

loadImage('https://example.com/image.jpg')
  .then((img) => {
    console.log('Image loaded successfully');
    document.body.appendChild(img);
  })
  .catch((error) => {
    console.error(error.message);
  });

Promise.prototype.then()

then()方法接受两个可选参数:onFulfilled和onRejected,分别表示成功时和失败时的回调函数。当Promise对象的状态为fulfilled时,会立即执行onFulfilled回调函数,并将操作结果作为参数传递给该函数;当Promise对象的状态为rejected时,会立即执行onRejected回调函数,并将拒绝原因(错误信息)作为参数传递给该函数。

案例

const p = new Promise((resolve, reject) => {
  resolve(1);
});

p.then(
  (res) => {
    console.log(res); // 输出:1
    return 2; // 返回值会被作为下一个then的输入
  },
  (error) => {
    console.log(error);
  }
)
.then(
  (res) => {
    console.log(res); // 输出:2
  }
);

Promise.prototype.catch()

catch()方法是then(undefined, onRejected)的语法糖,用于捕获Promise对象被rejected时的错误信息。

案例

const p = new Promise((resolve, reject) => {
  reject('error');
});

p.then((res) => {
  console.log(res); // 不会执行
})
.catch((error) => {
  console.log(error); // 输出:error
});

1.1.promise.all

过程:

1.创建promise数组:首先,需要创建一个包含多个promise对象的数组,每个promise对象都代表一个异步操作。

2.调用promise.all:然后调用promise.all方法,并将这个数组作为参数传递给它。promise.all会返回一个新的promise对象

3.处理结果:

如果所有的输入promiase对象都成功解析,那么promise.all返回的promise对象也会被解析,并且它的解析值是一个数组,包含了所有输入promise对象的解析值,顺序与输入数组一致。

如果任何一个输入promise对象被拒绝,那么promise.all返回的promise对象也会被拒绝,并且它的拒绝原因与第一个被拒绝的promise对象的拒绝原因相同。

4.使用.then和.catch:可以使用.then方法来处理成功的情况,使用.catch方法来处理失败的情况

例子:同时加载多张图片

const urls = [
  'https://example.com/image1.jpg',
  'https://example.com/image2.jpg',
  'https://example.com/image3.jpg'
];

const loadImage = (url) => {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => {
      resolve(img);
    };
    img.onerror = () => {
      reject(new Error(`Failed to load image from ${url}`));
    };
    img.src = url;
  });
};

Promise.all(urls.map(loadImage))
  .then((images) => {
    console.log('All images loaded successfully');
    images.forEach((img) => {
      document.body.appendChild(img);
    });
  })
  .catch((error) => {
    console.error(error.message);
  });

1.2.promise.race

过程:

1.创建promise数组:首先,需要创建一个包含多个promise对象的数组,每个promise对象都代表一个异步操作。

2.调用promise.race:然后调用promise.race方法,并将这个数组作为参数传递给它。promise.race会返回一个新的promise对象

3.处理结果:

promise.race只关心第一个完成的promise对象(无论是成功还是拒绝)

如果第一个完成的promise是成功解析的,那么promise.race返回的promise对象也会解析,并且它的解析值与第一个完成的promise对象的解析值相同

如果过第一个完成的promise是被拒绝的,那么promise.race返回的promise对象也会被拒绝,并且它的拒绝原因第一个被决绝的promise对象的拒绝原因相同

4.使用.then和.catch:同样,也可以使用.then方法;来处理成功的情况,使用.catch方法来处理失败的情况。

例子:同时加载多张图片,但只显示第一张加载成功的图片

const urls = [
  'https://example.com/image1.jpg',
  'https://example.com/image2.jpg',
  'https://example.com/image3.jpg'
];

const loadImage = (url) => {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => {
      resolve(img);
    };
    img.onerror = () => {
      reject(new Error(`Failed to load image from ${url}`));
    };
    img.src = url;
  });
};

Promise.race(urls.map(loadImage))
  .then((img) => {
    console.log('First image loaded successfully');
    document.body.appendChild(img);
  })
  .catch((error) => {
    console.error(error.message);
  });
// 创建两个异步操作的Promise,其中一个会更快完成
const slowFetch = () => new Promise((resolve) => {
  setTimeout(() => resolve('Slow Data'), 2000);
});

const fastFetch = () => new Promise((resolve) => {
  setTimeout(() => resolve('Fast Data'), 500);
});

// 使用 Promise.race 来等待第一个异步操作完成
Promise.race([slowFetch(), fastFetch()])
  .then((data) => {
    // 由于 fastFetch 更快完成,所以这里会输出 'Fast Data'
    console.log(data); // 输出: 'Fast Data'
  })
  .catch((error) => {
    // 如果没有任何Promise被拒绝,这里的catch不会被调用
    console.error(error);
  });

// 另一个例子,包含一个会被拒绝的Promise
const fetchWithTimeout = () => {
  return Promise.race([
    fetch('https://jsonplaceholder.typicode.com/posts/1') // 一个真实的fetch请求
      .then(response => response.json()),
    new Promise((_, reject) => {
      setTimeout(() => reject(new Error('Request timed out')), 1000); // 1秒后拒绝
    })
  ]);
};

// 使用 fetchWithTimeout,并处理可能的超时
fetchWithTimeout()
  .then(post => {
    console.log(post); // 如果fetch请求在1秒内完成,这里会输出post数据
  })
  .catch(error => {
    console.error('Error:', error.message); // 如果fetch请求超时,这里会输出 'Error: Request timed out'
  });

在这个fetchWithTimeout的例子中,我们使用了promise.race来设置一个超时机制。如果fetch请求在1秒内没有完成,那么promise.race会返回被拒绝的promise,并且我们可以在.catch中处理这个超时错误。

promise.resolve()和promise.reject()

promise.resolve()方法返回一个已经成功状态的promise对象,并将指定的值作为参数传递给它的then方法。

promise.reject()方法返回一个已经失败状态的promise对象,并将指定原因作为参数传递给它的catch方法
案例:

// Promise.resolve()
Promise.resolve(10)
  .then((value) => {
    console.log(`The value is ${value}`); // 输出:The value is 10
  })
  .catch((error) => {
    console.error(error.message); // 不会执行
  });

// Promise.reject()
Promise.reject('error')
  .then((value) => {
    console.log(value); // 不会执行
  })
  .catch((reason) => {
    console.log(reason); // 输出:error
  });

二、高阶语法与特性

2.1模板字符串的高级用法

本小节讲解模板字符串的嵌套、标签模板等高级用法,了解它们如何用于字符串的格式化、插值等操作。

2.1.1.模板字符串的嵌套

模板字符串允许嵌套另一个模板字符串,这在处理复杂数据结构时非常有用。例如,假设有一个包含地址信息的数组,可以使用嵌套模板字符串来生成一个HTML表格:

const addrs = [
  { first: 'John', last: 'Doe' },
  { first: 'Jane', last: 'Smith' }
];

const tmpl = addrs => `
  <table>
    ${addrs.map(addr => `
      <tr><td>${addr.first}</td></tr>
      <tr><td>${addr.last}</td></tr>
    `).join('')}
  </table>
`;

console.log(tmpl(addrs));

上述代码中,内部的模板字符串用于生成每一行的表格内容,外部的模板字符串则负责将这些行组合成一个完整的表格。

2.1.2.标签模板用于字符串的格式化、插值等操作

标签模板(Tagged Template)是一种特殊的函数,它允许对模板字符串进行自定义处理。标签模板函数的基本语法是在一个函数名后面紧跟一个模板字符串字面量。这个函数会接收两个参数:一个由模板字符串中的静态文本部分组成的数组,以及由模板字符串中的表达式求值结果组成的剩余参数列表。

1.字符串格式化

可以创建一个标签模板函数来格式化日期、数字或货币等。例如,以下是一个简单的标签模板函数,用于将数字格式化为货币形式:

function formatCurrency(strings, ...values) {
  let result = '';
  for (let i = 0; i < strings.length; i++) {
    result += strings[i];
    if (i < values.length) {
      result += '$' + values[i].toFixed(2); // 将数字格式化为两位小数的货币形式
    }
  }
  return result;
}

const price = 123.456;
console.log(formatCurrency`The price is ${price}`); // 输出 "The price is $123.46"
2.字符串插值:

标签模板函数也可以用于字符串插值,但与普通的模板字符串插值不同,标签模板函数可以对插入的变量或表达式进行自定义处理。例如,以下是一个将字符串转换为大写的标签模板函数:

function upperCase(strings, ...values) {
  return strings.reduce((result, str, i) => {
    const value = values[i - 1] || '';
    return result + str + value.toUpperCase();
  }, '');
}

const greeting = upperCase`Hello, ${'world'}!`; // 输出 "Hello, WORLD!"
3. 避免XSS攻击

在处理用户输入时,标签模板函数还可以用于避免跨站脚本攻击(XSS)。例如,可以对用户输入进行HTML转义

function escapeHTML(strings, ...values) {
  let result = '';
  for (let i = 0; i < strings.length; i++) {
    result += strings[i];
    if (i < values.length) {
      // 简单的HTML转义函数
      const escape = (html) => html.replace(/[&<>"'`=\/]/g, (s) => `&#${s.charCodeAt(0)};`);
      result += escape(values[i]);
    }
  }
  return result;
}

const userInput = '<script>alert("XSS!");</script>';
console.log(escapeHTML`Safe input: ${userInput}`); 
// 输出 "Safe input: &lt;script&gt;alert(&quot;XSS!&quot;);&lt;/script&gt;"

三、尾调用优化

3.1.尾调用优化(Tail Call Optimization)的概念和作用

尾调用优化是编译器或解释器对函数调用的一种优化手段。当函数A的最后一步是调用另一个函数B,并且A的返回值就是B的调用结果时,这个调用就被称为尾调用。如果编译器或解释器支持尾调用优化,那么在执行尾调用时,可以只保留函数B的调用记录,而删除函数A的调用记录,因为A的调用结果已经确定并且不再需要A的调用记录。这种优化可以显著减少内存使用,避免因为递归调用过深而导致的栈溢出错误。

3.2.递归函数中的尾调用优化

在递归函数中,尾调用优化尤为重要。传统的递归调用可能会导致大量的栈空间被占用,因为每次递归调用都会创建一个新的栈帧。而尾调用优化可以确保只有一个栈帧被重复使用,从而避免了栈空间的无谓消耗。

3.3.举例说明

已计算阶乘的递归函数为例,非尾递归和尾递归的实现方式如下:

非尾递归实现:

function factorial_recursive(n) {
  if (n === 0) {
    return 1;
  } else {
    return n * factorial_recursive(n - 1); // 这里不是尾调用,因为乘法操作在调用之后
  }
}

在这个非尾递归的实现中,每次递归调用之后都有一个乘法操作,因此这不是一个尾调用。编译器无法对这个递归调用进行优化。

尾递归实现:

function factorial_tail_recursive(n, result = 1) {
  if (n === 0) {
    return result;
  } else {
    return factorial_tail_recursive(n - 1, n * result); // 这里是尾调用,因为调用之后没有其他操作
  }
}

在这个尾递归的实现中,递归调用是函数的最后一个操作,并且这个调用的返回值就是整个函数的返回值。因此,编译器可以对这个递归调用进行优化,通过重用当前栈帧来避免增加额外的栈空间。

3.4.如何应用尾调用优化

要将一个递归函数改写为尾递归函数,通常需要引入一个辅助参数来保存中间结果。这个辅助参数在每次递归调用时都会被更新,并在递归结束时返回最终结果。

例2:计算斐波那契数列

非尾递归实现:

function fibonacci_non_tail_recursive(n) {
  if (n <= 1) {
    return n;
  } else {
    return fibonacci_non_tail_recursive(n - 1) + fibonacci_non_tail_recursive(n - 2);
  }
}

这个非尾递归的实现导致大量的重复计算和栈空间消耗。

尾递归实现

function fibonacci_tail_recursive(n, a = 0, b = 1) {
  if (n === 0) {
    return a;
  } else if (n === 1) {
    return b;
  } else {
    return fibonacci_tail_recursive(n - 1, b, a + b);
  }
}

在这个尾递归的实现中,我们引入了两个辅助参数 a 和 b 来保存斐波那契数列的前两个数。每次递归调用时,我们都会更新这两个参数,并在递归结束时返回最终结果。由于递归调用是函数的最后一个操作,并且这个调用的返回值就是整个函数的返回值,因此编译器可以对这个递归调用进行优化。

 四、模块化进阶

4.1.动态导入

4.1.1.基本语法

动态导入使用import()函数,该函数返回一个Promise对象。这意味着你可以使用.then()方法或async/await语法来处理导入的模块。以下是动态导入的常见写法:

1.导入整个模块:

import('./module.js').then((module) => {
  // 使用 module
});

2.导入模块的特定导出

import('./module.js').then(({ export1, export2 }) => {
  // 使用 export1 和 export2
});

4.1.2.动态导入的特点与优势

按需加载:动态导入允许你在需要时才加载模块,这有助于减少初始加载时间,提高应用性能。

代码分割:结合构建工具(如Webpack),动态导入可以实现代码分割,将代码拆分成更小的块,以便更高效地加载和执行。

条件加载:你可以根据条件动态加载不同的模块,这在实现功能切换或按需加载特定功能时非常有用。

4.1.3.动态导入的应用场景

按需加载组件:在单页面应用(SPA)中,你可以使用动态导入来按需加载组件,从而减少初始加载时间和内存占用。

条件加载模块:根据用户的操作或环境变量等条件,动态加载不同的模块以实现功能切换。

优化性能:通过代码分割和按需加载,动态导入可以显著提高应用的加载速度和性能。

4.1.4示例

使用动态导入根据条件加载不同模块

// 定义一个函数,根据不同的条件导入不同的模块
function loadModule(condition) {
  if (condition === 'moduleA') {
    return import('./moduleA.js');
  } else {
    return import('./moduleB.js');
  }
}

// 使用 loadModule() 函数来动态导入模块
loadModule('moduleA').then((module) => {
  // 使用 moduleA 模块
}).catch((error) => {
  // 处理错误
});

loadModule('moduleB').then((module) => {
  // 使用 moduleB 模块
}).catch((error) => {
  // 处理错误
});

在这个示例中,我们定义了一个loadModule函数,它根据传入的条件动态加载不同的模块。然后,我们使用loadModule函数来导入模块,并在Promisethen方法中使用相应的模块。

4.1.5.注意事项

兼容性:虽然大多数现代浏览器都支持动态导入,但在一些旧版浏览器中可能无法使用。因此,在开发过程中需要注意兼容性问题。

构建工具:为了充分利用动态导入的优势,通常需要结合构建工具(如Webpack)进行代码分割和优化。

错误处理:在使用动态导入时,需要妥善处理可能出现的错误,以确保应用的稳定性和用户体验。

4.2.循环依赖

循环依赖指的是两个或多个模块之间互相引用,形成一个闭环的依赖关系。这种依赖关系可能会导致一些潜在的问题,如模块加载顺序错误、未定义或未初始化的变量等。

4.2.1.循环依赖的定义与示例

循环依赖通常发生在以下情况:模块A依赖于模块B的导出,同时模块B也依赖于模块A的导出。这种依赖关系形成了一个闭环,可能导致模块加载和执行时的错误。

例如,有以下连个模块文件:

// a.js
import { b } from './b.js';

export const a = () => {
  console.log('This is a.js');
  b();
};

// b.js
import { a } from './a.js';

export const b = () => {
  console.log('This is b.js');
  a();
};

在这个例子中,a.jsb.js互相引用对方,形成了一个循环依赖。

4.2.2.循环依赖的问题与影响

1.加载顺序问题:在循环依赖的情况下,模块的加载顺序变得不确定。这可能导致某些模块在还未完全初始化的情况下就被其他模块引用,从而引发错误。

2.未定义或未初始化的变量:由于加载顺序的不确定性,可能会出现某些变量在引用时还未被定义或初始化的情况。

3.性能问题:循环依赖可能导致模块加载和执行的效率降低,因为模块之间的依赖关系变得更加复杂。

4.2.3.解决循环依赖的方法

1.重构代码:通过重构代码来消除循环依赖。例如,可以将一些公共的功能或数据提取到一个新的模块中,并让其他模块都依赖于这个新模块。

2.使用异步加载:在ES6中,可以使用动态导入(import())来异步加载模块。这有助于在需要时才加载模块,从而避免循环依赖的问题。但需要注意的是,异步加载可能会增加代码的复杂性和加载时间。

3.依赖注入:通过依赖注入模式来管理模块之间的依赖关系。这有助于降低模块之间的耦合度,并使得依赖关系更加清晰和可控。

4.使用第三方库或工具:一些第三方库或工具(如Webpack的splitChunks插件)可以帮助开发者更好地管理和优化模块之间的依赖关系。

4.2.4.最佳实践与建议

1.避免循环依赖:在设计模块时,应尽量避免循环依赖的发生。通过合理的模块划分和组织,可以降低循环依赖的风险。

2.清晰的模块接口:确保每个模块都有清晰的接口和职责。这有助于其他模块更容易地理解和使用它们,并降低循环依赖的可能性。

3.使用构建工具:利用构建工具(如Webpack、Rollup等)来优化模块之间的依赖关系。这些工具可以帮助开发者更好地管理模块、减少打包文件的大小并提高加载速度。

亲爱的友友们~~~码这么多字不容易啊 给孩子点点赞叭,评论个1也成呐

当然上述内容若有遗漏或不足之处,恳请各位大佬不吝赐教,指正并帮助美化,以期更加完善。

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

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

相关文章

Excel使用-弹窗“此工作簿包含到一个或多个可能不安全的外部源的链接”的发生与处理

文章目录 前言一、探讨问题发生原因1.引入外部公式2.引入外部数据验证二、问题现象排查及解决1.排查公式2.排查数据验证3.特殊处理方式总结前言 作为一种常用的办公软件,Excel被大家所熟知。尽管使用了多年,有时候在使用Excel时候也会发生一些不太常见的现象,需要用心核查下…

递归(3)----力扣40组合数2,力扣473火柴拼正方形

给定一个候选人编号的集合 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 注意&#xff1a;解集不能包含重复的组合。 示例 1: 输入: candidates [10,1,2,7,6,1…

CCF-第七届AIOps国际挑战赛-季军方案分享|北航-EasyRAG

历经4个月的时间&#xff0c;从初赛赛道第1&#xff0c;复赛赛道第2&#xff0c;到最后决赛获得季军&#xff0c;这一路我们团队收获了很多实践经验&#xff0c;也结识了不少业界的RAG研究者&#xff0c;受益匪浅。应组委会邀请&#xff0c;本文介绍一下我们EasyRAG方案的亮点和…

Spring Boot出现java: 错误: 无效的源发行版:16的解决方式

第一步&#xff1a; 修改为SDK的目标字节码版本 第二步&#xff1a;CtrlShiftAltS进入项目结构 第三步&#xff1a;pom.xml文件中 在网上搜索和自己SDK适配的Springboot版本&#xff0c;1.8对应的是2.7.1&#xff08;可以用&#xff09; 修改Java版本为1.8 最后的最后&a…

Redis学习 ——缓存

文章目录 一、Redis缓存的介绍二、Redis缓存问题2.1 缓存穿透2.2 缓存击穿2.3 缓存雪崩2.4 双写一致性2.5 缓存持久化RDBAOF 三、缓存数据管理3.1 数据过期策略3.2 数据淘汰策略 一、Redis缓存的介绍 我们在日常的代码编写中比较少使用到Redis&#xff0c;但是如果涉及到了比较…

【开源免费】基于Vue和SpringBoot的在线考试系统(附论文)

本文项目编号 T 624 &#xff0c;文末自助获取源码 \color{red}{T624&#xff0c;文末自助获取源码} T624&#xff0c;文末自助获取源码 网络的广泛应用给生活带来了十分的便利。所以把在线考试管理与现在网络相结合&#xff0c;利用java技术建设在线考试系统&#xff0c;实现…

git-.git目录解析

目录 .git目录下的文件信息 logs&#xff1a;记录各个分支日志记录 refs&#xff1a;记录本地分支、远程分支、tag标签最新commitID config: 配置信息&#xff0c;详细内容解析看下面介绍HEAD: 工作空间当前所在分支 inde文件: 它又常被称为“暂存区”或“缓存区”。这个文件…

sglang 部署Qwen2VL7B,大模型部署,速度测试,深度学习

sglang 项目github仓库&#xff1a; https://github.com/sgl-project/sglang 项目说明书&#xff1a; https://sgl-project.github.io/start/install.html 资讯&#xff1a; https://github.com/sgl-project/sgl-learning-materials?tabreadme-ov-file#the-first-sglang…

前端pdf预览方案

前端pdf预览方案 pdf预览一般不需要前端生成pdf文件&#xff0c;pdf文件一般是通过接口&#xff0c;获取pdf文件【responseType:‘blob’,】或二进制文件流【responseType: ‘arraybuffer’,】或者已有的pdf文件。 前端PDF预览通常是通过读取现有的PDF文件&#xff0c;并使用…

Kotlin return与return@forEachIndexed

Kotlin return与returnforEachIndexed fun main() {val data arrayOf(0, 1, 2, 3, 4)println("a")data.forEachIndexed { index, v ->if (v 2) {//类似while循环中的continue//跳过&#xff0c;继续下一个forEachIndexed迭代returnforEachIndexed}println("…

MATLAB绘制克莱因瓶

MATLAB绘制克莱因瓶 clc;close all;clear all;warning off;% clear all rand(seed, 100); randn(seed, 100); format long g;% Parameters u_range linspace(0, 2*pi, 100); v_range linspace(0, pi, 50); [U, V] meshgrid(u_range, v_range);% Parametric equations for t…

DDRPHY数字IC后端设计实现系列专题之数字后端floorplanpowerplan设计

3.2.3 特殊单元的布局 布图阶段除了布置 I/O 单元和宏单元&#xff0c;在 28nm 制程工艺时&#xff0c;还需要处理两种特 殊的物理单元&#xff0c;Endcap 和 Tapcell。 DDRPHY数字IC后端设计实现系列专题之后端设计导入&#xff0c;IO Ring设计 &#xff08;1&#xff09;拐…

css uniapp背景图宽度固定高度自适应可以重复

page {height: 100%;background-image: url(https://onlinekc.a.hlidc.cn/uploads/20241115/350f94aaf493d05625a7ddbc86c7804e.png);background-repeat: repeat;background-size: contain;} 如果不要重复 把background-repeat: repeat;替换background-repeat: no-repeat;

CC工具箱使用指南:【CAD导出界址点Excel】

一、简介 群友定制工具。 面图层导出界址点Excel表之前已经做过好几个&#xff0c;这个工具则是将CAD导出Excel。 CAD数据如下&#xff1a; 工具将如上截图中的边界线导出界址点Excel&#xff0c;并记录下面内的文字。 二、工具参数介绍 点击【定制工具】组里的【CAD导出界…

输出比较简介

输出比较简介 主要是用来输出PWM波形&#xff0c;这个波形是驱动电机的&#xff08;智能车和机器人等&#xff09;必要条件 OC&#xff08;Output Compare&#xff09;输出比较&#xff0c;还有IC&#xff0c;全称是Input Capture&#xff0c;意为输入捕获&#xff0c;还有CC…

力扣(leetcode)题目总结——辅助栈篇

leetcode 经典题分类 链表数组字符串哈希表二分法双指针滑动窗口递归/回溯动态规划二叉树辅助栈 本系列专栏&#xff1a;点击进入 leetcode题目分类 关注走一波 前言&#xff1a;本系列文章初衷是为了按类别整理出力扣&#xff08;leetcode&#xff09;最经典题目&#xff0c…

unity老猿随笔

下面是我最近开始整理的一些unity的基础知识和疑难杂症&#xff0c;如果大家有什么可以分享出来的经验&#xff0c;可以评论区留言&#xff0c;验证后整理进来&#xff0c;全猿学习&#xff01;如果有不对的地方&#xff0c;也欢迎指正&#xff0c;避免误人子弟&#xff01; l…

『VUE』30. 生命周期的介绍(详细图文注释)

目录 生命周期生命周期的8阶段生命周期小例子总结 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 生命周期 每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤&#xff0c;比如设置好数据侦听&#xff0c;编译模板&#xf…

Go语言跨平台桌面应用开发新纪元:LCL、CEF与Webview全解析

开篇寄语 在Go语言的广阔生态中&#xff0c;桌面应用开发一直是一个备受关注的领域。今天&#xff0c;我将为大家介绍三款基于Go语言的跨平台桌面应用开发框架——LCL、CEF与Webview&#xff0c;它们分别拥有独特的魅力和广泛的应用场景。通过这三款框架&#xff0c;你将能够轻…

华为HCCDA云技术认证--网络服务

大家好呀&#xff01;我是reload。今天继续带大家学习华为HCCDA云技术认证&#xff0c;涵盖华为云最为核心的计算、存储、网络、数据库、安全、部署等服务。今天学习网络服务相关内容。 登录华为云官网&#xff1a;https://www.huaweicloud.com/ &#xff0c;进入首页&#xff…