裸辞8年前端的面试笔记——JavaScript篇(一)
裸辞后的第二个月开始准备找工作,今天是第三天目前还没有面试,现在的行情是一言难尽,都在疯狂的压价。
下边是今天复习的个人笔记
一、事件循环
JavaScript 的事件循环(Event Loop)是其实现异步编程的关键机制。
从原理上讲,JavaScript 是单线程语言,只有一个主线程来执行代码,这意味着同一时间只能做一件事。但为了实现异步操作(比如处理用户交互、网络请求等),引入了事件循环机制。
事件循环涉及到几个重要概念:
- 调用栈(Call Stack): 是一种数据结构,用于记录函数的调用关系。函数调用时入栈,执行完毕后出栈。
- 任务队列(Task Queue): 也叫消息队列,用于存放异步操作的回调函数。当异步操作完成时,对应的回调函数会被放入任务队列。
- 宏任务(Macrotask): 包括 script (整体代码)、setTimeout、setInterval、setImmediate(Node.js 环境)、requestAnimationFrame 等。
- 微任务(Microtask): 包括 Promise 的 then、catch、finally,MutationObserver 等。
事件循环的执行过程大致如下:
- 首先执行调用栈中的同步任务。
- 当遇到异步任务时,异步任务会被挂起,不会阻塞主线程,继续执行同步任务。
- 当同步任务执行完毕后,开始处理微任务队列,依次执行微任务队列中的任务。
- 微任务执行完毕后,开始执行宏任务队列中的任务,每执行一个宏任务,就会检查并执行微任务队列。
- 重复上述过程,不断循环,这就是事件循环。
例如:
console.log('start');setTimeout(() => {console.log('setTimeout');
}, 0);Promise.resolve().then(() => {console.log('Promise then');
});console.log('end');
在这段代码中,首先 console.log('start')
和 console.log('end')
作为同步任务在调用栈中依次执行。setTimeout 是宏任务,会被放到宏任务队列。Promise.resolve().then()
是微任务,会被放到微任务队列。当同步任务执行完后,开始执行微任务队列中的 Promise
的 then
回调,打印 Promise then
,最后执行宏任务队列中的 setTimeout
回调,打印 setTimeout
。
二、Promise.all 和 Promise.race
Promise.all 和 Promise.race ,它们都是 Promise 的静态方法,在处理多个 Promise 时非常有用,以下是它们的详细介绍:
Promise.all
- 它接受一个包含多个
Promise
对象的可迭代对象(比如数组)作为参数。 - 只有当传入的所有
Promise
都成功时,Promise.all 才会返回一个成功的Promise
,其结果是一个包含所有Promise
结果的数组,顺序和传入的Promise
顺序一致。 - 只要有一个
Promise
失败,Promise.all
就会立即返回一个失败的Promise
,失败原因就是第一个失败的Promise
的原因。
例如:
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = Promise.resolve(3);Promise.all([promise1, promise2, promise3]).then((values) => {console.log(values); //输出: [1, 2, 3]}).catch((error) => {console.error(error);});
有失败的Promise
:
const promise1 = Promise.resolve(1);
const promise2 = Promise.reject(new Error('Promise 2 failed'));
const promise3 = Promise.resolve(3);Promise.all([promise1, promise2, promise3]).then((values) => {console.log(values); // 不会输出}).catch((error) => {console.error(error.message); // 输出: Promise 2 failed});
Promise.race
- 同样接受一个包含多个
Promise
对象的可迭代对象作为参数。 - 只要其中一个
Promise
率先改变状态(无论是成功还是失败),Promise.race
就会返回这个Promise
的结果或原因。
例如:
const promise1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('Promise 1 resolved');}, 2000);
});const promise2 = new Promise((resolve, reject) => {setTimeout(() => {reject(new Error('Promise 2 failed'));}, 1000);
});Promise.race([promise1, promise2]).then((value) => {console.log(value);}).catch((error) => {console.error(error.message); // Promise 2 failed});
简单来说,Promise.all
强调所有 Promise
都成功,Promise.race
则关注谁先改变状态。
纯JS实现Promise,并集成all和race
下面是一个简单实现 Promise 并添加 all 和 race 方法的代码示例,解释了其基本原理和实现思路:
// 自定义Promise类
function MyPromise(executor) {this.status = 'pending';this.value = null;this.reason = null;this.onResolvedCallbacks = [];this.onRejectedCallbacks = [];const resolve = (val) => {if (this.status === 'pending') {this.status = 'fulfilled';this.value = val;this.onResolvedCallbacks.forEach(callback => callback(this.value));}};const reject = (err) => {if (this.status === 'pending') {this.status ='rejected';this.reason = err;this.onRejectedCallbacks.forEach(callback => callback(this.reason));}};try {executor(resolve, reject);} catch (error) {reject(error);}
}// Promise.prototype.then方法实现
MyPromise.prototype.then = function (onFulfilled, onRejected) {onFulfilled = typeof onFulfilled === 'function'? onFulfilled : value => value;onRejected = typeof onRejected === 'function'? onRejected : reason => { throw reason };let nextPromise;if (this.status === 'fulfilled') {nextPromise = new MyPromise((resolve, reject) => {try {const x = onFulfilled(this.value);resolvePromise(nextPromise, x, resolve, reject);} catch (error) {reject(error);}});}if (this.status ==='rejected') {nextPromise = new MyPromise((resolve, reject) => {try {const x = onRejected(this.reason);resolvePromise(nextPromise, x, resolve, reject);} catch (error) {reject(error);}});}if (this.status === 'pending') {nextPromise = new MyPromise((resolve, reject) => {this.onResolvedCallbacks.push((value) => {try {const x = onFulfilled(value);resolvePromise(nextPromise, x, resolve, reject);} catch (error) {reject(error);}});this.onRejectedCallbacks.push((reason) => {try {const x = onRejected(reason);resolvePromise(nextPromise, x, resolve, reject);} catch (error) {reject(error);}});});}return nextPromise;
};// 辅助函数,处理then方法中返回值的逻辑
function resolvePromise(promise2, x, resolve, reject) {if (promise2 === x) {return reject(new TypeError('Chaining cycle detected for promise'));}if (x instanceof MyPromise) {x.then(resolve, reject);} else if (typeof x === 'object' || typeof x === 'function') {if (x === null) {return resolve(x);}let called = false;try {const then = x.then;if (typeof then === 'function') {then.call(x,(y) => {if (called) return;called = true;resolvePromise(promise2, y, resolve, reject);},(r) => {if (called) return;called = true;reject(r);});} else {resolve(x);}} catch (error) {if (called) return;called = true;reject(error);}} else {resolve(x);}
}// 实现Promise.all方法
MyPromise.all = function (promises) {return new MyPromise((resolve, reject) => {const result = [];let count = 0;if (promises.length === 0) {resolve(result);} else {promises.forEach((p, index) => {MyPromise.resolve(p).then((value) => {result[index] = value;count++;if (count === promises.length) {resolve(result);}}).catch((error) => {reject(error);});});}});
};// 实现Promise.race方法
MyPromise.race = function (promises) {return new MyPromise((resolve, reject) => {promises.forEach((p) => {MyPromise.resolve(p).then((value) => {resolve(value);}).catch((error) => {reject(error);});});});
};
使用自定义的 MyPromise
:
// 使用示例
const promise1 = new MyPromise((resolve) => {setTimeout(() => {resolve(1);}, 1000);
});const promise2 = new MyPromise((resolve, reject) => {setTimeout(() => {reject(new Error('Promise 2 failed'));}, 500);
});// 使用then方法
promise1.then((value) => {console.log(value);}).catch((error) => {console.error(error);});// 使用all方法
MyPromise.all([promise1, promise2]).then((values) => {console.log(values);}).catch((error) => {console.error(error);});// 使用race方法
MyPromise.race([promise1, promise2]).then((value) => {console.log(value);}).catch((error) => {console.error(error);});
在上述代码中,首先定义了一个 MyPromise 类,实现了基本的 Promise 功能,包括 then 方法。然后添加了 all 和 race 静态方法,分别用于按顺序处理多个 Promise(all)和谁先有结果就返回谁(race)。resolvePromise 函数则处理了 then 方法中返回值的复杂逻辑,确保遵循 Promise/A+ 规范。
三、闭包
闭包是面试中常见的一个考点,复习也是很有必要的,在工作中使用闭包的场景很多比如在Vue和React组件就是个大闭包,还有防抖节流等函数的封装等等。
1. 什么是闭包?
闭包是指函数和与其相关的词法环境的组合。当一个内部函数在其外部函数返回后仍然能访问外部函数的变量时,就创建了闭包。
function outer() {let count = 0;function inner() {count++;console.log(count);}return inner;
}const closureFn = outer();
closureFn(); // 1
closureFn(); // 2
在这个例子中,inner
函数形成了闭包,即使 outer
函数已经执行完毕,inner
函数依然可以访问 outer
函数作用域内的 count
变量。
2. 闭包有什么作用?
- 数据私有性: 可以隐藏变量,通过闭包,外部代码无法直接访问函数内部的变量,只能通过闭包返回的函数来操作这些变量,实现数据的封装。
- 状态保存: 闭包能记住创建时的状态,比如在计数器的例子中,每次调用闭包函数,都能记住上次 count 的值并进行操作。
- 柯里化: 闭包是实现函数柯里化的基础,柯里化可以将多参数函数转化为一系列单参数函数,提高函数的复用性和灵活性。柯里化后边会延伸描述
3. 闭包可能会带来什么问题?
- 内存泄漏: 如果闭包函数一直存在,并且引用了一些大的对象或不再需要的变量,这些变量不会被垃圾回收机制回收,可能会导致内存占用过高,出现内存泄漏。例如:
function createBigObject() {const bigArray = new Array(1000000).fill(0);return function () {// 闭包函数一直存在,bigArray无法被回收console.log('closure');}; }const leakyClosure = createBigObject();
- 变量的值不是预期的: 在循环中使用闭包时,如果不注意,可能会得到意外的结果。比如:
可以通过立即执行函数或使用const functions = []; for (var i = 0; i < 5; i++) {functions.push(() => {console.log(i);}); } functions.forEach(fn => fn()); // 输出 5 5 5 5 5,因为这里的i是最后循环结束时的值
let
关键字来解决这个问题。如下:const functions = []; for (let i = 0; i < 5; i++) {functions.push(() => {console.log(i);}); } functions.forEach(fn => fn()); // 输出 0 1 2 3 4
4. 如何避免闭包导致的内存泄漏?
当闭包不再使用时,手动将闭包函数赋值为 null
,这样相关的变量就可以被垃圾回收机制回收。例如:
function createClosure() {let data = { a: 1 };return function () {console.log(data.a);};
}let closureFn = createClosure();
// 使用闭包函数
closureFn();
// 不再使用闭包时,将其赋值为null
closureFn = null;
5. 实际开发中,不专门手动将闭包引用的变量置为null
实际开发中,闭包导致的内存泄漏本质是 “外部引用未正确释放”,而非闭包语法本身的问题。现代 GC 机制和框架已能处理大部分场景,手动置空闭包变量既不现实也无必要。开发者的核心任务是:
- 正确管理外部依赖(移除事件监听、清除定时器、避免不合理的全局引用);
- 依赖框架的生命周期钩子处理副作用,让闭包随上下文自然释放。
只有在极端或不规范的场景下,才需针对性地手动清理,但这也应优先通过切断外部引用来实现,而非直接操作闭包内部的变量。
四、柯里化
**柯里化(Currying)**是一种在函数式编程中广泛使用的技术,它允许你将一个多参数函数转换为一系列单参数函数。以下从定义、原理、用途、示例等方面详细介绍柯里化。
定义与原理
- 定义: 柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。简单来说,就是将一个多参数函数拆分成多个单参数函数。
- 原理: 利用闭包的特性,让函数记住之前传入的参数,当参数数量达到原函数所需的参数数量时,执行原函数逻辑。
用途
参数复用: 当多次调用同一个函数,并且传递的参数大部分相同时,使用柯里化可以复用这些相同的参数。
延迟计算: 可以在需要的时候再传入剩余的参数进行计算,而不是一次性传入所有参数。
动态创建函数: 根据不同的参数动态生成不同的函数。
示例
以下是一个简单的 JavaScript 示例,展示如何实现柯里化:
// 定义一个普通的加法函数
function add(a, b) {return a + b;
}// 实现柯里化函数
function curry(func) {return function curried(...args) {if (args.length >= func.length) {return func.apply(this, args);} else {return function (...nextArgs) {return curried.apply(this, args.concat(nextArgs));};}};
}// 将 add 函数进行柯里化
const curriedAdd = curry(add);// 使用柯里化函数
const add5 = curriedAdd(5);
console.log(add5(3)); // 输出 8
代码解释
- curry 函数: 接受一个函数 func 作为参数,返回一个新的函数 curried。
- curried 函数: 接受任意数量的参数 args,如果 args 的长度大于或等于原函数 func 的参数长度,则直接调用 func 并返回结果;否则,返回一个新的函数,该函数会将之前的参数和新传入的参数合并后再次调用 curried 函数。
- curriedAdd 函数: 是 add 函数柯里化后的结果。通过 curriedAdd(5) 得到一个新的函数 add5,这个函数记住了之前传入的参数 5,当调用 add5(3) 时,将 5 和 3 相加并返回结果。
实际应用场景
- **日志记录:**在日志记录时,通常会有一些固定的参数(如日志级别、日志来源等),可以使用柯里化来复用这些参数。
function log(level, source, message) {console.log(`[${level}] [${source}] ${message}`); }const curriedLog = curry(log); const errorLog = curriedLog('ERROR'); const appErrorLog = errorLog('App'); appErrorLog('Something went wrong!'); // 输出 [ERROR] [App] Something went wrong!
- 事件处理: 在处理事件时,可能需要传递一些额外的参数,可以使用柯里化来动态创建事件处理函数。
在这个示例中,通过柯里化创建了一个带有固定消息的事件处理函数<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"> </head><body><button id="myButton">Click me</button><script>function handleClick(message, event) {console.log(`${message}: ${event.type}`);}const curriedHandleClick = curry(handleClick);const clickWithMessage = curriedHandleClick('Button clicked');const button = document.getElementById('myButton');button.addEventListener('click', clickWithMessage);</script> </body></html>
clickWithMessage
,当按钮被点击时,会输出相应的日志信息。
不推荐使用柯里化的场景
- 简单一次性调用: 若函数仅调用一次,且参数无复用可能,直接调用普通函数更高效(如
sum(1, 2, 3)
无需柯里化)。 - 参数顺序依赖强或易混淆: 柯里化要求严格按参数顺序传参,若参数含义不明确(如
log('ERROR', 'App', '消息')
中 ‘App’ 可能是来源或消息),可能导致调用时参数错位。 - 追求极致性能的场景: 虽然现代引擎优化较好,但柯里化涉及闭包和多层函数嵌套,在极端高频调用(如循环内)时可能存在微小性能损耗(需实测验证)
总结
- 用: 当需要参数复用、延迟计算、函数组合或动态生成定制函数,且代码风格兼容函数式思维时。
- 慎: 当参数逻辑复杂、可读性可能受损,或团队对 FP 不熟悉时,优先考虑更直观的参数传递方式(如对象、默认参数)。
柯里化的核心价值在于将 “不变的部分” 与 “变化的部分” 分离,通过函数的 “预配置” 提高代码的灵活性和复用性。实际开发中,可从小规模场景(如工具函数、配置类函数)开始尝试,逐步判断是否符合项目需求。
相关文章:
裸辞8年前端的面试笔记——JavaScript篇(一)
裸辞后的第二个月开始准备找工作,今天是第三天目前还没有面试,现在的行情是一言难尽,都在疯狂的压价。 下边是今天复习的个人笔记 一、事件循环 JavaScript 的事件循环(Event Loop)是其实现异步编程的关键机制。 从…...
TCP 与 UDP报文
** TCP 与 UDP报文** 1. 引言 在网络通信中,TCP(传输控制协议) 和 UDP(用户数据报协议) 是两种最核心的传输层协议。它们各自适用于不同的场景,理解其工作原理对开发高性能网络应用至关重要。本文将详细解…...
开上“Python跑的车”——自动驾驶数据可视化的落地之道
开上“Python跑的车”——自动驾驶数据可视化的落地之道 一、自动驾驶离不开“看得见”的智能 在智能汽车时代,自动驾驶已然不是“炫技”标签,而是一场技术实力的全面拉锯战。而在这场战役中,有一个极其关键但常被忽略的领域,叫做: 数据可视化(Data Visualization)。 为…...

Linux中安装mysql8,转载及注意事项
一、先前往官网下载mysql8 下载地址: https://dev.mysql.com/downloads/选择Linux 二、删除Linux中的mysql(如果有的话),上传安装包 1、先查看mysql是否存在,命令如下: rpm -qa|grep -i mysql如果使用这…...
可以下载blender/fbx格式模型网站
glbxz.com glbxz.com可以下载blender/fbx格式模型。当然里面有免费的...

SpringBoot的汽车商城后台管理系统源码开发实现
概述 汽车商城后台管理系统专为汽车4S店和经销商设计,提供全面的汽车管理系统解决方案。 主要内容 1. 核心功能模块 系统提供以下主要功能: 销售管理:记录销售信息,跟踪交易进度客户管理:维护客户…...
从入门到深入:Vue.js 学习全攻略
一、Vue.js 入门基础 (一)Vue.js 简介与环境搭建 Vue.js 是一套用于构建用户界面的渐进式 JavaScript 框架,所谓渐进式,意味着开发者可以根据项目需求,灵活地选择使用 Vue 的功能。它既可以嵌入到简单的 HTML 页面中…...
C++八股--6--mysql 日志与并发控制
这里向大家介绍一下数据库基础:共分为以下章节 10前序.日志系统 这是数据库的核心。我放到首页来介绍,给大家一个前置概念,方便进行更好的学习 日志文件我们用来记录事务对数据库更新操作的文件,分为以记录为单位的文件和数据块…...

DeepSeek实战--手搓实现Agent
1.背景 要学习AI agent,只会用agent 框架,还不够,一旦框架出现问题,没法快速的排查出问题。 学习就应该“知其然,更应该知其所以然” ,今天我们就用编码的方式实现一个简单的agent 。我们模拟一套AI学生评…...
Hutool的`BeanUtil.toBean`方法详解
BeanUtil.toBean是Hutool工具包中一个非常实用的JavaBean转换工具方法,它能够方便地将一个对象(通常是Map或另一个JavaBean)转换为目标类型的JavaBean实例。 方法签名 public static <T> T toBean(Object source, Class<T> tar…...

线性代数——行列式⭐
目录 一、行列式的定义⭐ 1-1、三阶行列式练习 1-2、下面介绍下三角行列式、上三角行列式、对角行列式 编辑 二、行列式的性质 2-1、性质1,2,3,4,5,6 编辑 2-2、性质7 2- 3、拉普拉斯定理、克莱姆法则 三…...

iPhone手机连接WiFi异常解决方法
iPhone手机连接WiFi异常解决方法 一、问题现象二、iPhone连不上可能的原因三、基础排查与快速修复第一步:重启大法第二步:忽略网络,重新认证第三步:关闭“私有无线局域网地址”第四步:修改DNS服务器第五步:还原网络设置四、路由器端排查及设置关闭MAC地址过滤或添加到白名…...
Spark缓存
生活中缓存容量受成本和体积限制(比如 CPU 缓存只有几 MB 到几十 MB),但会通过算法(如 “最近最少使用” 原则)智能决定存什么,确保存的是 “最可能被用到的数据”。 1. 为什么需要缓存? 惰性执…...
计算机视觉与深度学习 | 基于Transformer的低照度图像增强技术
基于Transformer的低照度图像增强技术通过结合Transformer的全局建模能力和传统图像增强理论(如Retinex),在保留颜色信息、抑制噪声和平衡亮度方面展现出显著优势。以下是其核心原理、关键公式及典型代码实现: 一、原理分析 1. 全局依赖建模与局部特征融合 Transformer的核…...

学习设计模式《八》——原型模式
一、基础概念 原型模式的本质是【克隆生成对象】; 原型模式的定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象 。 原型模式的功能: 1、通过克隆来创建新的对象实例; 2、为克隆出来的新对象实例复制…...

疗愈服务预约小程序源码介绍
基于ThinkPHP、FastAdmin和UniApp开发的疗愈服务预约小程序源码,这款小程序在功能设计和用户体验上都表现出色,为疗愈行业提供了一种全新的服务模式。 该小程序源码采用了ThinkPHP作为后端框架,保证了系统的稳定性和高效性。同时,…...
如何通过外网访问内网?对比5个简单的局域网让互联网连接方案
在实际应用中,常常需要从外网访问内网资源,如远程办公访问公司内部服务器、在家访问家庭网络中的设备等。又或者在本地内网搭建的项目应用需要提供互联网服务。以下介绍几种常见的外网访问内网、内网提供公网连接实现方法参考。 一、公网IP路由器端口映…...
Linux 服务器静态 IP 配置初始化指南
✅ 第一步:确认网络管理方式 运行以下命令判断系统使用的网络管理服务: # 检查 NetworkManager 是否活跃 systemctl is-active NetworkManager# 检查 network(旧服务)是否活跃 systemctl is-active network或者检查配置路径&…...

【随笔】Google学术:but your computer or network may be sending automated queries.
文章目录 一、问题复述二、问题原因三、解决 前提:你的xxx是自己做的,你自己可以管理,而不是用的那些劣质✈场。 一、问题复述 🟢如下图所示:可以打开谷歌学术,但是一搜索就是这个界面。 二、问题原因 …...

长事务:数据库中的“隐形炸弹“——金仓数据库运维避坑指南
引言:凌晨三点的告警 "张工!生产库又告警了!"凌晨三点的电话铃声总是格外刺耳。运维团队发现数据库频繁进入单用户模式,排查发现某核心表的年龄值(Age)已突破20亿大关。经过一夜奋战,…...

ubuntu nobel + qt5.15.2 设置qss语法识别正确
问题展示 解决步骤 首选项里面的高亮怎么编辑选择都没用。如果已经有generic-highlighter和css.xml,直接修改css.xml文件最直接! 在generic-highlighter目录下找到css.xml文件,位置是:/opt/Qt/Tools/QtCreator/share/qtcreator/…...
优化01-统计信息
Oracle 的统计信息是数据库优化器生成高效执行计划的核心依据。它记录了数据库对象(如表、索引、列等)的元数据信息,帮助优化器评估查询成本并选择最优执行路径。以下是关于 Oracle 统计信息的详细介绍: 一、统计信息的分类 表统…...

Unity-Socket通信实例详解
今天我们来讲解socket通信。 首先我们需要知道什么是socket通信: Socket本质上就是一个个进程之间网络通信的基础,每一个Socket由IP端口组成,熟悉计网的同学应该知道IP主要是应用于IP协议而端口主要应用于TCP协议,这也证明了Sock…...

MATLAB仿真定点数转浮点数(对比VIVADO定点转浮点)
MATLAB仿真定点数转浮点数 定点数可设置位宽,小数位宽;浮点数是单精度浮点数 对比VIVADO定点转浮点 目录 前言 一、定点数 二、浮点数 三、定点数转浮点数 四、函数代码 总结 前言 在FPGA上实现算法时,相比MATLAB实现往往需要更长的开发…...
配置Jupyter Notebook环境及Token认证(Linux服务器)
配置Jupyter Notebook环境及Token认证(Linux服务器) 背景 在Ubuntu 18.04.6 LTS服务器(IP: 39.105.167.2)上,基于虚拟环境pytorch_env,通过Mac终端(SSH)配置Jupyter Notebook环境&…...

【计算机网络】Cookie、Session、Token之间有什么区别?
大家在日常使用浏览器时可能会遇到:是否清理Cookie?这个问题。 那么什么是Cookie呢?与此相关的还有Session、Token这些。这两个又是什么呢? 本文将对这三个进行讲解区分,如果对小伙伴有帮助的话,也请点赞、…...

SpringCloud服务拆分:Nacos服务注册中心 + LoadBalancer服务负载均衡使用
SpringCloud中Nacos服务注册中心 LoadBalancer服务负载均衡使用 前言Nacos工作流程nacos安装docker安装window安装 运行nacos微服务集成nacos高级特性1.服务集群配置方法效果图模拟服务实例宕机 2.权重配置3.环境隔离 如何启动集群节点本地启动多个节点方法 LoadBalancer集成L…...
Spring AI 集成 DeepSeek V3 模型开发指南
Spring AI 集成 DeepSeek V3 模型开发指南 前言 在人工智能飞速发展的当下,大语言模型不断推陈出新,DeepSeek AI 推出的开源 DeepSeek V3 模型凭借其卓越的推理和问题解决能力备受瞩目。与此同时,Spring AI 作为一个强大的框架,…...

Apache Doris 使用指南:从入门到生产实践
目录 一、Doris 核心概念 1.1 架构组成 1.2 数据模型 二、Doris 部署方式 2.1 单机部署(测试环境) 2.2 集群部署(生产环境) 三、数据操作指南 3.1 数据库与表管理 3.2 数据导入方式 3.2.1 批量导入 3.2.2 实时导入 3.…...

26届秋招收割offer指南
26届暑期实习已经陆续启动,这也意味着对于26届的同学们来说,“找工作”已经提上了日程。为了帮助大家更好地准备暑期实习和秋招,本期主要从时间线、学习路线、核心知识点及投递几方面给大家介绍,希望能为大家提供一些实用的建议和…...