JavaScript教程(十三)--- 使用 Promise

使用 Promise

Promise 是一个对象,它代表了一个异步操作的最终完成或者失败。因为大多数人仅仅是使用已创建的 Promise 实例对象,所以本教程将首先说明怎样使用 Promise,再说明如何创建 Promise。

本质上 Promise 是一个函数返回的对象,我们可以在它上面绑定回调函数,这样我们就不需要在一开始把回调函数作为参数传入这个函数了。

假设现在有一个名为 createAudioFileAsync() 的函数,它接收一些配置和两个回调函数,然后异步地生成音频文件。一个回调函数在文件成功创建时被调用,另一个则在出现异常时被调用。

以下为使用 createAudioFileAsync() 的示例:

// 成功的回调函数
function successCallback(result) {console.log("音频文件创建成功:" + result);
}// 失败的回调函数
function failureCallback(error) {console.log("音频文件创建失败:" + error);
}createAudioFileAsync(audioSettings, successCallback, failureCallback);

如果重写 createAudioFileAsync() 为返回 Promise 的形式,你可以把回调函数附加到它上面:

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);

这种形式有若干优点,下面我们将会逐一讨论。

链式调用

连续执行两个或者多个异步操作是一个常见的需求,在上一个操作执行成功之后,开始下一个的操作,并带着上一步操作所返回的结果。在旧的回调风格中,这种操作会导致经典的回调地狱:

doSomething(function (result) {doSomethingElse(result, function (newResult) {doThirdThing(newResult, function (finalResult) {console.log(`得到最终结果:${finalResult}`);}, failureCallback);}, failureCallback);
}, failureCallback);

有了 Promise,我们就可以通过一个 Promise 链来解决这个问题。这就是 Promise API 的优势,因为回调函数是附加到返回的 Promise 对象上的,而不是传入一个函数中。

见证奇迹的时刻:then() 函数会返回一个和原来不同的新的 Promise

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);

promise2 不仅表示 doSomething() 函数的完成,也代表了你传入的 successCallback 或者 failureCallback 的完成,这两个函数也可以返回一个 Promise 对象,从而形成另一个异步操作,这样的话,在 promise2 上新增的回调函数会排在这个 Promise 对象的后面。

就像这样,每一个 Promise 都代表了链中另一个异步过程的完成。此外,then 的参数是可选的,catch(failureCallback) 等同于 then(null, failureCallback)——所以如果你的错误处理代码对所有步骤都是一样的,你可以把它附加到链的末尾:

doSomething().then(function (result) {return doSomethingElse(result);}).then(function (newResult) {return doThirdThing(newResult);}).then(function (finalResult) {console.log(`得到最终结果:${finalResult}`);}).catch(failureCallback);

你或许会看到这种形式的箭头函数:

JSCopy to Clipboard

doSomething().then((result) => doSomethingElse(result)).then((newResult) => doThirdThing(newResult)).then((finalResult) => {console.log(`得到最终结果:${finalResult}`);}).catch(failureCallback);

注意:一定要有返回值,否则,回调将无法获取上一个 Promise 的结果。(如果使用箭头函数,() => x 比 () => { return x; } 更简洁一些,但后一种保留 return 的写法才支持使用多个语句)。如果上一个处理程序启动了一个 Promise 但并没有返回它,那就没有办法再追踪它的状态了,这个 Promise 就是“漂浮”的。

doSomething().then((url) => {// 忘记返回了!fetch(url);}).then((result) => {// 结果是 undefined,因为上一个处理程序没有返回任何东西。// 无法得知 fetch() 的返回值,不知道它是否成功。});

如果有竞争条件的话,情况会更糟——如果上一个处理程序的 Promise 没有返回,那么下一个 then 处理程序会提前调用,而它读取的任何值都可能是不完整的。

const listOfIngredients = [];doSomething().then((url) => {// 忘记返回了!fetch(url).then((res) => res.json()).then((data) => {listOfIngredients.push(data);});}).then(() => {console.log(listOfIngredients);// 永远是 [],因为 fetch 请求还没有完成。});

因此,一个经验法则是,每当你的操作遇到一个 Promise,就返回它,并把它的处理推迟到下一个 then 处理程序中。

const listOfIngredients = [];doSomething().then((url) =>fetch(url).then((res) => res.json()).then((data) => {listOfIngredients.push(data);}),).then(() => {console.log(listOfIngredients);});// 或doSomething().then((url) => fetch(url)).then((res) => res.json()).then((data) => {listOfIngredients.push(data);}).then(() => {console.log(listOfIngredients);});

嵌套

对比上述两个例子,第一个例子中有一个 Promise 链嵌套在另一个 then() 处理程序的返回值中;而第二个例子则是完全扁平化的链。简洁的 Promise 链式编程最好保持扁平化,不要嵌套 Promise,因为嵌套经常会是粗心导致的。详见常见错误。

嵌套 Promise 是一种可以限制 catch 语句的作用域的控制结构写法。明确来说,嵌套的 catch 只会捕获其作用域及以下的错误,而不会捕获链中更高层的错误。如果使用正确,可以实现高精度的错误恢复。

doSomethingCritical().then((result) =>doSomethingOptional() // 可选操作.then((optionalResult) => doSomethingExtraNice(optionalResult)).catch((e) => {console.log(e.message);}),) // 即便可选操作失败了,也会继续执行.then(() => moreCriticalStuff()).catch((e) => console.log(`严重失败:${e.message}`));

注意,这里的可选操作是嵌套的——缩进并不是原因,而是因为可选操作被外层的 ( 和 ) 括号包裹起来了。

这个内部的 catch 语句仅能捕获到 doSomethingOptional() 和 doSomethingExtraNice() 的失败,并将该错误与外界屏蔽,之后就恢复到 moreCriticalStuff() 继续执行。值得注意的是,如果 doSomethingCritical() 失败,这个错误仅会被最后的(外部)catch 语句捕获到,并不会被内部 catch 吞掉。

Catch 的后续链式操作

有可能会在一个回调失败之后继续使用链式操作,即,使用一个 catch,这对于在链式操作中抛出一个失败之后,再次进行新的操作会很有用。请阅读下面的例子:

new Promise((resolve, reject) => {console.log("初始化");resolve();
}).then(() => {throw new Error("有哪里不对了");console.log("执行「这个」");}).catch(() => {console.log("执行「那个」");}).then(() => {console.log("执行「这个」,无论前面发生了什么");});

输出结果如下:

初始化
执行「那个」
执行「这个」,无论前面发生了什么

备注: 并没有输出“执行「这个」”,因为在第一个 then() 中的 throw 语句导致其被拒绝。

常见错误

在编写 Promise 链时,需要注意以下示例中展示的几个错误:

// 错误示例,包含 3 个问题!doSomething().then(function (result) {// 忘记返回 Promise + 不必要的嵌套doSomethingElse(result).then((newResult) => doThirdThing(newResult));}).then(() => doFourthThing());
// 忘记使用 catch 终止 Promise 链

第一个错误是没有正确地链接。当我们创建一个新 Promise 但忘记返回它时,就会发生这种情况。结果就是,这条链断掉了——或者更确切地说,我们有两个独立的链在竞争。这意味着 doFourthThing() 不会等待 doSomethingElse() 或 doThirdThing() 完成,而是会与它们同时运行——这很可能不是我们想要的。单独的链也有单独的错误处理,这会导致错误无法被捕获。

第二个错误是不必要的嵌套。嵌套限制了内部错误处理程序的作用域,如果不是有意为之,可能会导致未捕获的错误。该错误的一个变体是 Promise 构造函数反模式,它将一个 Promise 代码片段嵌入了另一个 Promise 构造函数里。

第三个错误是忘记用 catch 终止链。在大多数浏览器中,未终止的 Promise 链会导致 Promise 的拒绝事件无法被捕获。参见错误处理。

一个好的经验法则是总是返回或终止 Promise 链,并且一旦你得到一个新的 Promise,就立即返回它,最终的链应是扁平化的:

doSomething().then(function (result) {// 如果使用完整的函数表达式:返回 Promisereturn doSomethingElse(result);})// 如果使用箭头函数:省略大括号并隐式返回结果.then((newResult) => doThirdThing(newResult))// 即便上一个 Promise 返回了一个结果,后一个 Promise 也不一定非要使用它。// 你可以传入一个不使用前一个结果的处理程序。.then((/* 忽略上一个结果 */) => doFourthThing())// 总是使用 catch 终止 Promise 链,以保证任何未处理的拒绝事件都能被捕获!.catch((error) => console.error(error));

注意:() => x 是 () => { return x; } 的简写。

上述代码的写法就是具有适当错误处理的简单明确的链式写法。

使用 async/await 可以解决以上大多数错误,使用 async/await 时,最常见的语法错误就是忘记了 await 关键字。

错误处理

你或许还有印象,在之前的回调地狱示例中,有 3 次 failureCallback 的调用,而在 Promise 链中只有尾部的一次调用。

doSomething().then((result) => doSomethingElse(result)).then((newResult) => doThirdThing(newResult)).then((finalResult) => console.log(`得到最终结果:${finalResult}`)).catch(failureCallback);

通常,一遇到异常抛出,浏览器就会顺着 Promise 链寻找下一个 onRejected 失败回调函数或者由 .catch() 指定的回调函数。这和以下同步代码的工作原理(执行过程)非常相似。

try {let result = syncDoSomething();let newResult = syncDoSomethingElse(result);let finalResult = syncDoThirdThing(newResult);console.log(`得到最终结果:${finalResult}`);
} catch (error) {failureCallback(error);
}

这种异步代码的对称性在 async/await 语法中达到了极致:

async function foo() {try {const result = await doSomething();const newResult = await doSomethingElse(result);const finalResult = await doThirdThing(newResult);console.log(`得到最终结果:${finalResult}`);} catch (error) {failureCallback(error);}
}

这个例子是在 Promise 的基础上构建的,例如,doSomething() 与之前的函数是相同的。你可以在 async 函数和 await 参考中的与此语法相关的文章。

通过捕获所有的错误,甚至抛出异常和程序错误,Promise 解决了回调地狱的基本缺陷。这对于构建异步操作的基础功能而言是很有必要的。

Promise 拒绝事件

当一个 Promise 拒绝事件未被任何处理器处理时,它会冒泡到调用栈的顶部,主机需要将其暴露出来。在 Web 上,当 Promise 被拒绝时,会有下文所述的两个事件之一被派发到全局作用域(通常而言,就是 window;如果是在 web worker 中使用的话,就是 Worker 或者其他基于 worker 的接口)。这两个事件如下所示:

rejectionhandled

当 Promise 被拒绝、并且在 reject 函数处理该拒绝事件之后会派发此事件。

unhandledrejection

当 Promise 被拒绝,但没有提供 reject 函数来处理该拒绝事件时,会派发此事件。

上述两种事件(类型为 PromiseRejectionEvent)都有两个属性,一个是 promise 属性,该属性指向被拒绝的 Promise,另一个是 reason (en-US) 属性,该属性用来说明 Promise 被拒绝的原因。

因此,我们可以通过以上事件为 Promise 失败时提供补偿处理,也有利于调试 Promise 相关的问题。在每一个上下文中,该处理都是全局的,因此不管源码如何,所有的错误都会在同一个处理函数中被捕捉并处理。

在 Node.js 中,对拒绝事件的处理稍有不同。你可以通过为 Node.js 的 unhandledRejection 事件添加处理器(注意名称的大小写不同)来捕获未处理的拒绝,就像这样:

process.on("unhandledRejection", (reason, promise) => {/* 你可以在这里添加一些代码,以便检查 promise 和 reason */
});

对于 Node.js 来说,为了防止错误被记录到控制台(否则默认会发生),添加 process.on() 监听器就足够了;不需要类似浏览器运行时的 preventDefault() 方法这样的等效操作。

然而,如果你添加了 process.on 监听器,但没有在其中添加代码来处理被拒绝的 Promise,那么它们就会被丢弃,而且不会有任何提示。因此,最好在监听器中添加代码来检查每个被拒绝的 Promise,并确保它们不是由于代码错误而导致的。

组合

有四个组合工具可用来并发异步操作:Promise.all()、Promise.allSettled()、Promise.any() 和 Promise.race()。

我们可以同时启动所有操作,再等待它们全部完成,就像这样:

Promise.all([func1(), func2(), func3()]).then(([result1, result2, result3]) => {/* 使用 result1、result2 和 result3 */
});

如果数组中的某个 Promise 被拒绝,Promise.all() 就会立即拒绝返回的 Promise,并终止其他操作。这可能会导致一些意外的状态或行为。Promise.allSettled() 是另一个组合工具,它会等待所有操作完成后再处理返回的 Promise。

所有的这些方法都是并发运行 Promise 的——一系列 Promise 同时启动,而不是彼此等待。顺序执行也是可能的,这需要一些巧妙的 JavaScript 手段:

[func1, func2, func3].reduce((p, f) => p.then(f), Promise.resolve()).then((result3) => {/* 使用 result3 */});

在这个例子中,我们使用 reduce 把一个异步函数数组变为一个 Promise 链。上面的代码等同于:

Promise.resolve().then(func1).then(func2).then(func3).then((result3) => {/* 使用 result3 */});

我们也可以写成可复用的函数形式,这在函数式编程中极为普遍:

const applyAsync = (acc, val) => acc.then(val);
const composeAsync =(...funcs) =>(x) =>funcs.reduce(applyAsync, Promise.resolve(x));

composeAsync() 函数将会接受任意数量的函数作为其参数,并返回一个新的函数,而该函数又接受一个初始值,该组合的参数传递管线如下所示:

const transformData = composeAsync(func1, func2, func3);
const result3 = transformData(data);

顺序组合还可以使用 async/await 更简洁地完成:

let result;
for (const f of [func1, func2, func3]) {result = await f(result);
}
/* 使用最后的结果(即 result3)*/

然而,在你顺序组合 Promise 前,请考虑是否真的有必要——因为它们会阻塞彼此,除非一个 Promise 的执行依赖于另一个 Promise 的结果,否则最好并发运行 Promise。

在旧式回调 API 中创建 Promise

可以通过 Promise 的构造函数从零开始创建 Promise。这种方式(通过构造函数的方式)应当只在封装旧 API 的时候用到。

理想状态下,所有的异步函数应该会返回 Promise。但有一些 API 仍然使用旧方式来传入成功(或者失败)的回调。最典型的例子就是 setTimeout() (en-US) 函数:

setTimeout(() => saySomething("10 秒钟过去了"), 10 * 1000);

混用旧式回调和 Promise 可能会造成运行时序问题。如果 saySomething 函数失败了,或者包含了编程错误,那就没有办法捕获它了。这得怪 setTimeout

幸运地是,我们可以将 setTimeout 封装入 Promise 内。最好的做法是,将这些有问题的函数封装起来,留在底层,并且永远不要再直接调用它们:

const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));wait(10 * 1000).then(() => saySomething("10 秒钟")).catch(failureCallback);

通常,Promise 的构造函数接收一个执行函数(executor),我们可以在这个执行函数里手动地解决(resolve)或拒绝(reject)一个 Promise。既然 setTimeout 并不会真的执行失败,那么我们可以在这种情况下忽略拒绝的情况。你可以在 Promise() 参考中查看更多关于执行函数的信息。

时序

最后,我们将深入了解更多技术细节——关于注册的回调函数何时被调用。

保证

在基于回调的 API 中,回调函数何时以及如何被调用取决于 API 的实现者。例如,回调可能是同步调用的,也可能是异步调用的:

function doSomething(callback) {if (Math.random() > 0.5) {callback();} else {setTimeout(() => callback(), 1000);}
}

我们非常不建议使用上述这种设计,因为它会导致所谓的“Zalgo 状态”。在设计异步 API 的上下文中,这意味着回调在某些情况下是同步调用的,但在其他情况下是异步调用的,这为调用者带来的歧义。更多背景信息,请参见文章为异步设计 API,这是该术语首次被正式提出的地方。这种 API 设计使得副作用难以分析:

let value = 1;
doSomething(() => {value = 2;
});
console.log(value); // 1 还是 2?

另一方面,Promise 是一种控制反转的形式——API 的实现者不控制回调何时被调用。相反,维护回调队列并决定何时调用回调的工作被委托给了 Promise 的实现者,这样一来,API 的使用者和开发者都会自动获得强大的语义保证,包括:

  • 被添加到 then() 的回调永远不会在 JavaScript 事件循环的当前运行完成之前被调用。
  • 即使异步操作已经完成(成功或失败),在这之后通过 then() 添加的回调函数也会被调用。
  • 通过多次调用 then() 可以添加多个回调函数,它们会按照插入顺序进行执行。

以防万一的提醒:传入 then() 的函数永远不会被同步调用,即使 Promise 已经被解决了(resolved):

Promise.resolve().then(() => console.log(2));
console.log(1); // 1, 2

传入 then() 的函数不会立即运行,而是被放入微任务队列中,这意味着它会在稍后运行(仅在创建该函数的函数退出后,且 JavaScript 执行堆栈为空时),也就是在控制权返回事件循环之前。总而言之,不会等待太久:

const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));wait().then(() => console.log(4));
Promise.resolve().then(() => console.log(2)).then(() => console.log(3));
console.log(1); // 1, 2, 3, 4

任务队列 vs. 微任务

Promise 回调被处理为微任务,而 setTimeout() 回调被处理为任务队列。

const promise = new Promise((resolve, reject) => {console.log("Promise 执行函数");resolve();
}).then((result) => {console.log("Promise 回调(.then)");
});setTimeout(() => {console.log("新一轮事件循环:Promise(已完成)", promise);
}, 0);console.log("Promise(队列中)", promise);

上述代码的输出如下:

Promise 执行函数
Promise(队列中)Promise {<pending>}
Promise 回调(.then)
新一轮事件循环:Promise(已完成)Promise {<fulfilled>}

详见深入:微任务与 Javascript 运行时环境。

当 Promise 与 任务冲突时

你可能遇到如下情况:你的一些 Promise 和任务(例如事件或回调)会以不可预测的顺序启动。此时,你或许可以通过使用微任务检查状态或平衡 Promise,并以此有条件地创建 Promise。

如果你认为微任务可能会帮助你解决问题,那么请阅读微任务指南,学习如何用 queueMicrotask() 来将一个函数作为微任务添加到队列中。

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

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

相关文章

《黑马点评》Redis高并发项目实战笔记(上)P1~P43

P1 Redis企业实战课程介绍 P2 短信登录 导入黑马点评项目 首先在数据库连接下新建一个数据库hmdp&#xff0c;然后右键hmdp下的表&#xff0c;选择运行SQL文件&#xff0c;然后指定运行文件hmdp.sql即可&#xff08;建议MySQL的版本在5.7及以上&#xff09;&#xff1a; 下面这…

ArrayList部分底层源码分析

JDK版本为1.8.0_271&#xff0c;以插入和删除元素为例&#xff0c;部分源码如下&#xff1a; // 部分属性 transient Object[] elementData; // 底层数组 private int size; // 记录元素个数 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA {}; // 空Obje…

数据结构2:基于顺序表的通讯录项目

文章目录 头文件SeqList.hContact.h 实现文件SeqList.cContact.c 测试文件text.c 头文件 SeqList.h #pragma once#include<stdio.h> #include<stdlib.h> #include<assert.h> #include"Contact.h"#define INIT_CAPACITY 4//将顺序表数据类型调整为…

基于可变形卷积的大规模视觉基础模型的探索

基于可变形卷积的大规模视觉基础模型的探索 文章目录 基于可变形卷积的大规模视觉基础模型的探索一、简介二、亮点三、项目功能四、模型的应用1、图像模态任务性能2. 图文跨模态任务性能 五、源程序下载 一、简介 本模型包括大规模视觉基础模型"InternImage"&#x…

物联网实战--驱动篇之(五)TEA和AES加密算法

目录 一、前言 二、TEA算法 三、AES算法 四、加解密测试 五、安全性保障 一、前言 物联网的安全性是经常被提及的一个点&#xff0c;如果你的设备之间通讯没有加密的话&#xff0c;那么攻击者很容易就能获取并解析出报文的协议&#xff0c;从而根据攻击者的需要进行设备操…

MongoDB的安装和使用

1.MongoDB 安装 1.1 基于Docker安装 docker run --restartalways -d --name mongo -v /opt/mongodb/data:/data/db -p 27017:27017 mongo:4.0.6 1.2 客户端工具使用 MongoDB Compass | MongoDB 2.MongoDB 使用 2.1 引用依赖包 <dependency><groupId>org.sprin…

信号完整性的常见术语概念(面试常用)

目录 术语 概念一览 1&#xff0e;信号完整性&#xff08;Signal Integrity&#xff09; 2&#xff0e;传输线&#xff08;Transmission Line&#xff09; 3&#xff0e;特性阻抗&#xff08;Characteristic Impedance&#xff09; 4&#xff0e;反射&#xff08;Reflecti…

【环境搭建】ubuntu工作站搭建全流程(显卡4090)

安装ubuntu22.04系统 首先&#xff0c;先压缩windows分区&#xff0c;按住Win X快捷键&#xff0c;选择磁盘管理,压缩分区&#xff0c;压缩出新的分区用于安装ubuntu22.04 windows插入系统盘&#xff0c;点击重启&#xff0c;一直按F12,选择系统盘启动方式语言选择chinese–…

[react优化] 避免组件或数据多次渲染/计算

代码如下 点击视图x➕1,导致视图更新, 视图更细导致a也重新大量计算!!这很浪费时间 function App() {const [x, setX] useState(3)const y x 2console.log(重新渲染, x, y);console.time(timer)let a 0for (let index 0; index < 1000000000; index) {a}console.timeE…

【小红书校招场景题】12306抢票系统

1 坐过高铁吧&#xff0c;有抢过票吗。你说说抢票系统对于后端开发人员而言会有哪些情况&#xff1f; 对于后端开发人员来说&#xff0c;开发和维护一个高铁抢票系统&#xff08;如中国的12306&#xff09;会面临一系列的挑战和情况。这些挑战主要涉及系统的性能、稳定性、数据…

用ansys q3d提取pcb板上的寄生参数及注意事项

需求 画好pcb板后&#xff0c;想要提取回路的寄生参数 1 保存为ad格式 因为之前图方便用立创eda画的板子&#xff0c;结果无法导出成想要的格式。因此需要将立创eda的文件导出为ad格式。立创eda的官网有相关教程。 注意事项&#xff08;只说自己遇到的问题&#xff09; 导…

Ubuntu22.04 + ROS2 Humble的环境配置

Ubuntu22.04 ROS2 Humble的环境配置 文章目录 Ubuntu22.04 ROS2 Humble的环境配置(1) Set locale(2) Setup Sources(3)安装ROS2(4)检查是否成功安装 参考官方网站ROS2-Installation ROS2的各种版本及维护计划&#xff0c;可以参考ROS2-List of Distributions (1) Set locale…

Django中的静态文件、路径、访问静态文件的方法

1.什么是静态文件 不能与服务器端做动态交互的文件都是静态文件 如:图片,css,js,音频,视频,html文件(部分) 2.静态文件配置 在 settings.py 中配置一下两项内容: 1.配置静态文件的访问路径 通过哪个url地址找静态文件 STATIC_URL ‘/static/’ 说…

独一无二:探索单例模式在现代编程中的奥秘与实践

设计模式在软件开发中扮演着至关重要的角色&#xff0c;它们是解决特定问题的经典方法。在众多设计模式中&#xff0c;单例模式因其独特的应用场景和简洁的实现而广受欢迎。本文将从多个角度详细介绍单例模式&#xff0c;帮助你理解它的定义、实现、应用以及潜在的限制。 1. 什…

华为OD-C卷-结队编程[200分]

题目描述 某部门计划通过结队编程来进行项目开发, 已知该部门有 N 名员工,每个员工有独一无二的职级,每三个员工形成一个小组进行结队编程, 结队分组规则如下: 从部门中选出序号分别为 i、j、k 的3名员工,他们的职级分别为 level[i],level[j],level[k], 结队小组满…

FreeRTOS基本介绍

RTOS&#xff0c;Real Time Operating System&#xff0c;实时操作系统&#xff0c;是指具有实时性、能支持实时控制系统工作的操作系统。 它&#xff08;RTOS&#xff09;的首要任务是调动所有资源完成实时控制任务的工作&#xff08;确保实时性&#xff09;&#xff0c;其次才…

数据结构篇1—《顺序表》

文章目录 &#x1f6a9;前言1. 数据结构的概念2. 数据结构的分类3. 顺序表3.1. 顺序表的分类&#xff08;1&#xff09;静态顺序表&#xff08;2&#xff09;动态顺序表 4. 动态顺序表实现4.1. 实现步骤&#xff08;1&#xff09;框架结构&#xff08;2&#xff09;SeqList.h头…

【八股】MySQL

面试题 知道什么是覆盖索引吗&#xff1f; 覆盖索引是指&#xff0c;查询使用的索引&#xff0c;需要返回的列&#xff0c;在该索引的叶子节点中已经能够全部找到。 简单的来说&#xff0c;覆盖索引就是查询索引后&#xff0c;已经得到了所需字段的信息&#xff0c;不需要回表…

如何准备2024年汉字小达人:18道历年考题示例和解析、备考提醒

现在距离2024年第11届汉字小达人比赛还有六个多月的时间&#xff0c;如何利用这段时间有条不紊地备考呢&#xff1f;我的建议是两手准备&#xff1a;①把小学1-5年级的语文课本上的知识点熟悉&#xff0c;重点是字、词、成语、古诗。阅读理解不需要。②把历年真题刷刷熟&#x…

linux如何使 CPU使用率保持在指定百分比?

目录 方法1&#xff1a;&#xff08;固定在100%&#xff09; 方法2&#xff1a;&#xff08;可以指定0~100%&#xff09; 方法3&#xff1a;使用ChaosBlade工具&#xff08;0~100%&#xff09; 方法1&#xff1a;&#xff08;固定在100%&#xff09; for i in seq 1 $(cat /pro…