axios是如何实现的(源码解析)

news/发布时间2024/6/8 2:18:51

1 axios的实例与请求流程

在阅读源码之前,先大概了解一下axios实例的属性和请求整体流程,带着这些概念,阅读源码可以轻松不少!

下图是axios实例属性的简图。

可以看到axios的实例上,其实主要就这三个东西:

  1. config:配置,比如url、method、params、headers等等
  2. interceptors :拦截器,分为请求拦截器和返回拦截器。
  3. request:调用xhr或者http请求的方法,参数就是config

由于调用request方法的时候可以再次传入config,但是不能传入interceptors,所以拦截器一定是要在请求之前就在axios上添加好,不能临时加。

下图是axios的请求流程,其实相当简单,先了解这个流程,看源码的时候就会有方向。

2 源码文件结构解析

axios的源码都在lib文件夹下,最核心的内容在core文件夹里。

lib│  axios.js    // 最终导出的文件│  utils.js    // 工具类├─adapters     // 适配器相关│      adapters.js //适配器类│      http.js     // node请求│      xhr.js      // 浏览器请求├─cancel      // 取消功能相关│      CanceledError.js //取消异常类│      CancelToken.js   //取消token类│      isCancel.js      //判断是否取消├─core       // 核心功能相关 │      Axios.js                 // axios类│      AxiosError.js            // axios异常类│      AxiosHeaders.js          // 请求头│      buildFullPath.js         // 构造请求地址│      dispatchRequest.js       // 发送请求方法│      InterceptorManager.js    // 拦截器的类│      mergeConfig.js           // 合并配置方法│      settle.js                // 处理请求结果方法│      transformData.js         // 数据转换执行方法├─defaults    // 默认配置│      index.js                 // 默认请求参数配置│      transitional.js          // 默认transitional配置├─env        //  node环境没有FormData,│  │  data.js│  └─classes│          FormData.js├─helpers  // 各种工具类方法,看名字就可以大概猜到作用│      AxiosTransformStream.js│      AxiosURLSearchParams.js│      bind.js│      buildURL.js│      callbackify.js│      combineURLs.js│      cookies.js│      deprecatedMethod.js│      formDataToJSON.js│      formDataToStream.js│      fromDataURI.js│      HttpStatusCode.js│      isAbsoluteURL.js│      isAxiosError.js│      isURLSameOrigin.js│      null.js│      parseHeaders.js│      parseProtocol.js│      readBlob.js│      README.md│      speedometer.js│      spread.js│      throttle.js│      toFormData.js│      toURLEncodedForm.js│      validator.js│      ZlibHeaderTransformStream.js└─platform  // 为不同环境下准备的方法    │  index.js    ├─browser    │  │  index.js    │  └─classes    │          Blob.js    │          FormData.js    │          URLSearchParams.js    └─node        │  index.js        └─classes                FormData.js                URLSearchParams.js

3 源码文件阅读

3.1 入口文件 axios.js

该文件创建了一个axios实例,并且导出,所以我们import axios from 'axios'引入的就是该实例,可以直接使用,不需要再new Axios({...})这样写。

下面看一下axios实例是如何创建的吧~


// 核心方法,根据config创建axios实例
function createInstance (defaultConfig) {// 创建axios实例const context = new Axios(defaultConfig);// 给Axios原型上的request方法绑定context为它的this// 这个instance就是我们最终使用的axios// 没想到吧,最开始的instance其实是个函数,// 所以我们才可以使用这个用法axios('/api/url')// 只不过后面给它扩展了很多东西const instance = bind(Axios.prototype.request, context);// 将Axios.prototype上的属性都绑定到instance上,// 这样它就拥有了简写的请求方法,比如axios.get(),axios.post()// 如果是函数,this绑定为contextutils.extend(instance, Axios.prototype, context, { allOwnKeys: true });// 将context上的属性都绑定到instance上,// 这样它就拥有了拦截器属性,可以使用axios.interceptors.request.use()// 因为context上的函数的this本就指向context,所以第三个参数不需要再指定utils.extend(instance, context, null, { allOwnKeys: true });// 给instance增加create方法,可以通过create创建一个实例instance.create = function create (instanceConfig) {// 入参为拼接配置项,以instanceConfig为优先return createInstance(mergeConfig(defaultConfig, instanceConfig));};return instance;
}// 调用上面的方法,最终导出的是axios,
// 其实是Axios.prototype.request,并扩展了很多属性
const axios = createInstance(defaults);// 继续给axios增加属性
// 这就说明如果自己通过const myAxios=axios.create({});
// 创建出来的实例就没有下面这些属性了
// 所以下面这些属性只能通过import axios from 'axios';
// axios.all()这样的方式来使用axios.Axios = Axios;// Cancel相关
axios.CanceledError = CanceledError;
axios.CancelToken = CancelToken;
axios.isCancel = isCancel;
axios.VERSION = VERSION;
// 工具函数,将对象转为FormData
axios.toFormData = toFormData;// Axios通用异常类
axios.AxiosError = AxiosError;// Cancel异常类
axios.Cancel = axios.CanceledError;// Expose all/spread
// 工具函数
axios.all = function all (promises) {return Promise.all(promises);
};// 工具函数,利用apply将数组参数改为单个传入的参数
axios.spread = spread;// 判断异常是否是AxiosError
axios.isAxiosError = isAxiosError;// 合并config对象方法
axios.mergeConfig = mergeConfig;axios.AxiosHeaders = AxiosHeaders;// 工具方法
axios.formToJSON = thing => formDataToJSON(utils.isHTMLForm(thing) ? new FormData(thing) : thing);// 获取适配器:xhr 、http
axios.getAdapter = adapters.getAdapter;// 请求状态
axios.HttpStatusCode = HttpStatusCode;axios.default = axios;// 最终导出
export default axios

3.2 Axios类

从上面的文件可以看出,axios扩展了Axios的原型方法和Axios实例的属性,所以接下来要重点看Axios的类里有什么内容。


class Axios {// 可以看到Axios的构造函数相当简单// 仅仅是保存了我们传入的config,// 然后初始化空的拦截器对象constructor(instanceConfig) {// 所有的配置都设置再defaults上this.defaults = instanceConfig;// 初始化空的拦截器对象,包含请求拦截器request和返回拦截器responsethis.interceptors = {request: new InterceptorManager(),response: new InterceptorManager()};}// request是Axios的核心方法// 所有的核心都在request方法里,// request方法接收两种参数,【直接传config对象】或者【传url和config对象】request (configOrUrl, config) {// 允许axios('example/url'[, config]) 这样使用if (typeof configOrUrl === 'string') {config = config || {};config.url = configOrUrl;} else {config = configOrUrl || {};}// request会使用传入的配置merge默认配置// 所以即使只传了一个url,也会使用默认的Get方法config = mergeConfig(this.defaults, config);const { headers } = config;// 默认get请求config.method = (config.method || this.defaults.method || 'get').toLowerCase();// 说明header可以直接设置// 也可以在common设置通用header,也可以为每种请求设置特定的headerlet contextHeaders = headers && utils.merge(headers.common,headers[config.method]);headers && utils.forEach(['delete', 'get', 'head', 'post', 'put', 'patch', 'common'],(method) => {delete headers[method];});// 优先使用headers下配置,再使用headers.common和headers[get,post]的配置config.headers = AxiosHeaders.concat(contextHeaders, headers);// 请求拦截器链const requestInterceptorChain = [];// 记录是否使用同步的方式调用,我们配置拦截器的时候,默认是false,也就是异步let synchronousRequestInterceptors = true;this.interceptors.request.forEach(function unshiftRequestInterceptors (interceptor) {// 如果配置了runWhen函数,那么会先执行runWhen,如果为true,才会添加该拦截器if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {return;}synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;// unshift说明后传入的请求拦截器先执行,一次放入两个,分别是fulfilled和rejectedrequestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);});// 响应拦截器链const responseInterceptorChain = [];this.interceptors.response.forEach(function pushResponseInterceptors (interceptor) {// push说明先传入的响应拦截器先执行responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);});let promise;let i = 0;let len;// 默认是异步执行,也就是一个执行完再执行下一个if (!synchronousRequestInterceptors) {//dispatchRequest是真正的发送请求const chain = [dispatchRequest.bind(this), undefined];// 前面插入请求拦截器chain.unshift.apply(chain, requestInterceptorChain);// 后面插入响应拦截器chain.push.apply(chain, responseInterceptorChain);len = chain.length;promise = Promise.resolve(config);// 依次执行while (i < len) {promise = promise.then(chain[i++], chain[i++]);}return promise;}len = requestInterceptorChain.length;let newConfig = config;i = 0;// 同步执行,请求拦截器while (i < len) {const onFulfilled = requestInterceptorChain[i++];const onRejected = requestInterceptorChain[i++];try {newConfig = onFulfilled(newConfig);} catch (error) {onRejected.call(this, error);break;}}// 发起请求try {promise = dispatchRequest.call(this, newConfig);} catch (error) {return Promise.reject(error);}i = 0;len = responseInterceptorChain.length;// 返回有异常可以继续走下去while (i < len) {promise = promise.then(responseInterceptorChain[i++], responseInterceptorChain[i++]);}return promise;}// 获取请求地址getUri (config) {config = mergeConfig(this.defaults, config);const fullPath = buildFullPath(config.baseURL, config.url);return buildURL(fullPath, config.params, config.paramsSerializer);}
}// Provide aliases for supported request methods
// 给Axios原型注入四个请求方法,请求方法本质都是调用request方法
// 这四个都是不带请求体的
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData (method) {Axios.prototype[method] = function (url, config) {return this.request(mergeConfig(config || {}, {method,url,data: (config || {}).data}));};
});// 给Axios注入post,put,patch,postForm,putForm,patchForm方法
// 这几个方法都是带请求体的
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData (method) {function generateHTTPMethod (isForm) {return function httpMethod (url, data, config) {return this.request(mergeConfig(config || {}, {method,headers: isForm ? {'Content-Type': 'multipart/form-data'} : {},url,data}));};}Axios.prototype[method] = generateHTTPMethod();Axios.prototype[method + 'Form'] = generateHTTPMethod(true);
});export default Axios;

3.3 InterceptorManager类

接下来看看拦截器是如何实现的。

先回顾一下我们平时是怎么使用拦截器的?


axios.interceptors.request.use({fulfilled:()=>{},rejected:()=>{}
})

可以看到我们给use传递的是一个对象,对象包含fulfilled函数和rejected函数。

接下来看源码:

class InterceptorManager {// 构造函数只初始化了一个空的handlers数组// 拦截器就是放在这个数组里的constructor() {this.handlers = [];}// 添加拦截器,返回索引,可以用索引来移除拦截器// 可以发现除了fulfilled和rejected,// 我们还可以设置synchronous和runWhen// runWhen函数用来动态控制是否使用该拦截器use (fulfilled, rejected, options) {this.handlers.push({fulfilled,rejected,synchronous: options ? options.synchronous : false,runWhen: options ? options.runWhen : null});return this.handlers.length - 1;}// 根据添加时返回的索引去删除拦截器eject (id) {if (this.handlers[id]) {this.handlers[id] = null;}}// 清空拦截器clear () {if (this.handlers) {this.handlers = [];}}// 提供遍历拦截器快捷操作forEach (fn) {utils.forEach(this.handlers, function forEachHandler (h) {if (h !== null) {fn(h);}});}
}export default InterceptorManager;

3.4 dispatchRequest发送请求

看完上面的代码,我们已经基本搞清楚了axios的整体流程:

组装config->组装header->调用请求拦截器->发送实际请求->调用返回拦截器。

但是我们还不知道axios具体是如何调用请求的,那么接下来就要看dispatchRequest代码咯!


// 暂且先记住,这个函数的作用就是用来判断请求是否被取消,
// 如果要的话,则直接抛出异常,
function throwIfCancellationRequested (config) {if (config.cancelToken) {config.cancelToken.throwIfRequested();}if (config.signal && config.signal.aborted) {throw new CanceledError(null, config);}
}// 发送请求核心函数
export default function dispatchRequest (config) {// 刚开始请求前判断一次是否取消throwIfCancellationRequested(config);config.headers = AxiosHeaders.from(config.headers);// 执行数据转换操作config.data = transformData.call(config,config.transformRequest);// 默认设置请求头的contentType为application/x-www-form-urlencodedif (['post', 'put', 'patch'].indexOf(config.method) !== -1) {config.headers.setContentType('application/x-www-form-urlencoded', false);}// 获取适配器,如果是浏览器环境获取xhr,// 如果是Node环境,获取http // 适配器就是最终用来发送请求的东西const adapter = adapters.getAdapter(config.adapter || defaults.adapter);// 请求是使用适配器执行configreturn adapter(config).then(function onAdapterResolution (response) {// 请求完之后判断是否要取消throwIfCancellationRequested(config);// 对返回结果进行转换response.data = transformData.call(config,config.transformResponse,response);// 设置返回头response.headers = AxiosHeaders.from(response.headers);return response;}, function onAdapterRejection (reason) {// 如果不是因为取消而报错if (!isCancel(reason)) {// 再次判断是否要取消,如果是会抛出异常throwIfCancellationRequested(config);// 处理正常错误的返回值if (reason && reason.response) {reason.response.data = transformData.call(config,config.transformResponse,reason.response);reason.response.headers = AxiosHeaders.from(reason.response.headers);}}return Promise.reject(reason);});
}

3.5 adapter 请求适配器,此处以xhr请求适配器为例

dispatchRequest的流程还是相对简单的,剩下的疑惑就是adapter干了些什么,让我们接着往下看吧!


// 用于给上传和下载进度增加监听函数
function progressEventReducer (listener, isDownloadStream) {let bytesNotified = 0;const _speedometer = speedometer(50, 250);return e => {const loaded = e.loaded;const total = e.lengthComputable ? e.total : undefined;const progressBytes = loaded - bytesNotified;const rate = _speedometer(progressBytes);const inRange = loaded <= total;bytesNotified = loaded;const data = {loaded,total,progress: total ? (loaded / total) : undefined,bytes: progressBytes,rate: rate ? rate : undefined,estimated: rate && total && inRange ? (total - loaded) / rate : undefined,event: e};data[isDownloadStream ? 'download' : 'upload'] = true;listener(data);};
}// 判断是否支持XMLHttpRequest
const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';// 适配器的请求参数是config
export default isXHRAdapterSupported && function (config) {// 返回Promisereturn new Promise(function dispatchXhrRequest (resolve, reject) {// 请求体let requestData = config.data;// 请求头const requestHeaders = AxiosHeaders.from(config.headers).normalize();// 返回数据类型const responseType = config.responseType;let onCanceled;// function done () {if (config.cancelToken) {config.cancelToken.unsubscribe(onCanceled);}if (config.signal) {config.signal.removeEventListener('abort', onCanceled);}}// 自动帮我们设置contentType,// 这就是为什么我们使用的时候都不需要// 特别设置contentType的原因了if (utils.isFormData(requestData)) {if (platform.isStandardBrowserEnv || platform.isStandardBrowserWebWorkerEnv) {// 浏览器环境让浏览器设置requestHeaders.setContentType(false); } else {requestHeaders.setContentType('multipart/form-data;', false); }}// 请求let request = new XMLHttpRequest();// 设置auth,帮我们转码好了if (config.auth) {const username = config.auth.username || '';const password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : '';requestHeaders.set('Authorization', 'Basic ' + btoa(username + ':' + password));}// 拼接完整URL路径const fullPath = buildFullPath(config.baseURL, config.url);// 开启请求request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);// 设置超时时间request.timeout = config.timeout;//function onloadend () {if (!request) {return;}// 预准备返回体的内容const responseHeaders = AxiosHeaders.from('getAllResponseHeaders' in request && request.getAllResponseHeaders());const responseData = !responseType || responseType === 'text' || responseType === 'json' ?request.responseText : request.response;const response = {data: responseData,status: request.status,statusText: request.statusText,headers: responseHeaders,config,request};// 请求完之后判断请求是成功还是失败// 执行resolve和reject的操作settle(function _resolve (value) {resolve(value);done();}, function _reject (err) {reject(err);done();}, response);// 清除requestrequest = null;}if ('onloadend' in request) {// 设置onloadendrequest.onloadend = onloadend;} else {// Listen for ready state to emulate onloadendrequest.onreadystatechange = function handleLoad () {if (!request || request.readyState !== 4) {return;}// The request errored out and we didn't get a response, this will be// handled by onerror instead// With one exception: request that using file: protocol, most browsers// will return status as 0 even though it's a successful requestif (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {return;}// readystate handler is calling before onerror or ontimeout handlers,// so we should call onloadend on the next 'tick'// readystate之后再执行onloadendsetTimeout(onloadend);};}// 处理浏览器请求取消事件request.onabort = function handleAbort () {if (!request) {return;}reject(new AxiosError('Request aborted', AxiosError.ECONNABORTED, config, request));request = null;};// 处理低级的网络错误request.onerror = function handleError () {reject(new AxiosError('Network Error', AxiosError.ERR_NETWORK, config, request));request = null;};// 处理超时request.ontimeout = function handleTimeout () {let timeoutErrorMessage = config.timeout ? 'timeout of ' + config.timeout + 'ms exceeded' : 'timeout exceeded';const transitional = config.transitional || transitionalDefaults;if (config.timeoutErrorMessage) {timeoutErrorMessage = config.timeoutErrorMessage;}reject(new AxiosError(timeoutErrorMessage,transitional.clarifyTimeoutError ? AxiosError.ETIMEDOUT : AxiosError.ECONNABORTED,config,request));request = null;};// 添加 xsrfif (platform.isStandardBrowserEnv) {const xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath))&& config.xsrfCookieName && cookies.read(config.xsrfCookieName);if (xsrfValue) {requestHeaders.set(config.xsrfHeaderName, xsrfValue);}}// 无请求体的话就移除contentTyperequestData === undefined && requestHeaders.setContentType(null);// 添加headers if ('setRequestHeader' in request) {utils.forEach(requestHeaders.toJSON(), function setRequestHeader (val, key) {request.setRequestHeader(key, val);});}// 添加withCredentials if (!utils.isUndefined(config.withCredentials)) {request.withCredentials = !!config.withCredentials;}// 添加responseTypeif (responseType && responseType !== 'json') {request.responseType = config.responseType;}// 增加下载过程的监听函数if (typeof config.onDownloadProgress === 'function') {request.addEventListener('progress', progressEventReducer(config.onDownloadProgress, true));}// 增加上传过程的监听函数if (typeof config.onUploadProgress === 'function' && request.upload) {request.upload.addEventListener('progress', progressEventReducer(config.onUploadProgress));}// 请求过程中取消if (config.cancelToken || config.signal) {onCanceled = cancel => {if (!request) {return;}reject(!cancel || cancel.type ? new CanceledError(null, config, request) : cancel);request.abort();request = null;};config.cancelToken && config.cancelToken.subscribe(onCanceled);if (config.signal) {config.signal.aborted ? onCanceled() : config.signal.addEventListener('abort', onCanceled);}}// 获取请求协议,比如https这样的const protocol = parseProtocol(fullPath);// 判断当前环境是否支持该协议if (protocol && platform.protocols.indexOf(protocol) === -1) {reject(new AxiosError('Unsupported protocol ' + protocol + ':', AxiosError.ERR_BAD_REQUEST, config));return;}// 发送请求request.send(requestData || null);});
}

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

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

相关文章

npmjs官网(查询依赖包)

npmjs官网 可以方便的查看依赖包的安装、使用说明及相关注意事项等。 以wechat-http为例&#xff1a;

【黑马程序员】STL容器之string

string string 基本概念 string本质 string是c风格的字符串&#xff0c;而string本质上是一个类 string和char* 区别 char* 是一个指针string是一个类&#xff0c;类内部封装了char*,管理这个字符串&#xff0c;是一个char*型的容器 特点 string 内部封装了很多成员方法…

小程序--事件处理

一、事件对象 给小程序的事件传递参数&#xff0c;有以下两种方法&#xff1a; 1、自定义属性 <view class"item" wx:for"{{ 5 }}" wx:key"*this" data-index"{{index}}" bind:tap"onClick"></view> Page({o…

C#安装CommunityToolkit.Mvvm依赖

这里需要有一定C#基础&#xff0c; 首先找到右边的解决方案&#xff0c;右键依赖项 然后选择nuget管理 这里给大家扩展一下nuget的国内源&#xff08;https://nuget.cdn.azure.cn/v3/index.json&#xff09; 然后搜自己想要的依赖性&#xff0c;比如CommunityToolkit.Mvvm 再点…

vue中实现拖拽排序功能

npm i vuedraggable <template><div class"app-container"><!-- <div :class"canEdit ? dargBtn-lock el-icon-unlock : dargBtn-lock el-icon-lock" click"removeEvent()">{{ canEdit ? 调整 : 锁定 }}</div> --&…

Linux--自定义shell

shell shell就是操作系统提供给用户与操作系统进行交互的命令行界面。它可以理解为一个用户与操作系统之间的接口&#xff0c;用户可以通过输入命令来执行各种操作&#xff0c;如文件管理、进程控制、软件安装等。Shell还可以通过脚本编程实现自动化任务。 常见的Unix系统中使…

如何修改unity的背景颜色

要在Unity中将背景颜色设为黑色&#xff0c;可以按照以下步骤进行&#xff1a; 1、在Unity编辑器中&#xff0c;选择你想要修改背景颜色的摄像机对象&#xff08;一般是Main Camera&#xff09;。 2、在Inspector面板中&#xff0c;找到"Clear Flags"&#xff08;清…

后端经典面试题合集

目录 1. Java基础1-1. JDK 和 JRE 和 JVM 分别是什么&#xff0c;有什么区别&#xff1f;1-2. 什么是字节码&#xff1f;采用字节码的最大好处是什么&#xff1f;1-3. JDK 动态代理和 CGLIB 动态代理的区别是什么&#xff1f; 1. Java基础 1-1. JDK 和 JRE 和 JVM 分别是什么&…

使用 yarn 的时候,遇到 Error [ERR_REQUIRE_ESM]: require() of ES Module 怎么解决?

晚上回到家&#xff0c;我打开自己的项目&#xff0c;执行&#xff1a; cd HexoPress git pull --rebase yarn install yarn dev拉取在公司 push 的代码&#xff0c;然后更新依赖&#xff0c;最后开始今晚的开发时候&#xff0c;意外发生了&#xff0c;竟然报错了&#xff0c;…

【linux】查看openssl程序的安装情况

【linux】查看openssl程序的安装情况 1、查看安装包信息 $ rpm -qa |grep openssl 2、安装路径 $ rpm -ql openssl $ rpm -ql openssl-libs $ rpm -ql openssl-devel 3、相关文件和目录 /usr/bin/openssl /usr/include/openssl /usr/lib64/libssl.so.* /usr/lib64/libcrypto…

[golang] 24 fmt.Errorf(), error.Is() 和 error.As()

文章目录 一、默认的 error 实现二、自定义 error 实现2.1 通过 fmt.Errorf(%w) 创建嵌套 error2.1.1 fmt.Errorf() 实现 2.2 errors.Is()2.2.1 使用2.2.2 实现 2.3 errors.As()2.3.1 使用2.3.2 实现 一、默认的 error 实现 首先&#xff0c;go 定义了 error interface&#x…

跨区互联组网怎么做?SD-WAN专线可以实现吗?

在当今数字化时代&#xff0c;企业不断扩张&#xff0c;跨区域互联成为业务发展的必然需求。然而&#xff0c;跨区互联组网涉及到复杂的网络架构和连接&#xff0c;传统的网络方案往往难以满足高性能、高可靠性和低成本的要求。SD-WAN专线技术的出现&#xff0c;为跨区互联组网…

IO线程进程作业day6

1> 将标准io文件IO的内容复习一遍 2> 进程线程的相关函数复习一遍 3> 将信号和消息队列的课堂代码敲一遍 1、处理普通信号 #include <myhead.h> //定义信号处理函数 void handler(int signo) {if(signoSIGINT){puts("按下ctrlc");} } int main(in…

chatGPT 使用随想

一年前 chatGPT 刚出的时候&#xff0c;我就火速注册试用了。 因为自己就是 AI 行业的&#xff0c;所以想看看国际上最牛的 AI 到底发展到什么程度了. 自从一年前 chatGPT 火出圈之后&#xff0c;国际上的 AI 就一直被 OpenAI 这家公司引领潮流&#xff0c;一直到现在&#x…

创建型设计模式 - 原型设计模式 - JAVA

原型设计模式 一 .简介二. 案例三. 补充知识 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 一 .简介 原型模式提供了一种机制&#xff0c;可以将原始对象复制到新对象&#xff0…

突出最强算法模型——回归算法 !!

文章目录 1、特征工程的重要性 2、缺失值和异常值的处理 &#xff08;1&#xff09;处理缺失值 &#xff08;2&#xff09;处理异常值 3、回归模型的诊断 &#xff08;1&#xff09;残差分析 &#xff08;2&#xff09;检查回归假设 &#xff08;3&#xff09;Cooks 距离 4、学…

如何准确查询自己的大数据信用报告?

在当今数字化时代&#xff0c;大数据信用报告在个人信用评估中扮演着越来越重要的角色。然而&#xff0c;很多人可能不知道如何查询自己的大数据信用报告。本文贷大家一起了解一下&#xff0c;希望对你有帮助。 如何准确查询自己的大数据信用报告&#xff1a; 一、找到可靠的查…

学习Redis基础篇

1.初识Redis 1.认识NoSQL 2.认识Redis 3.连接redis命令 4.数据结构的介绍 5.通用命令 2.数据类型 1.String类型 常见命令&#xff1a;例子&#xff1a;set key value

(提供数据集下载)基于大语言模型LangChain与ChatGLM3-6B本地知识库调优:数据集优化、参数调整、Prompt提示词优化实战

文章目录 &#xff08;提供数据集下载&#xff09;基于大语言模型LangChain与ChatGLM3-6B本地知识库调优&#xff1a;数据集优化、参数调整、提示词Prompt优化本地知识库目标操作步骤问答测试的预设问题原始数据情况数据集优化&#xff1a;预处理&#xff0c;先后准备了三份数据…

【AI数字人-论文】RAD-NeRF论文

文章目录 前言模型框架动态的NeRF前处理头部模型音频特征眼部控制头部总体表示 躯干模型loss 结果参考 【AI数字人-论文】AD-NeRF论文 前言 本篇论文有三个主要贡献点&#xff1a; 提出一种分解的音频空间编码模块&#xff0c;该模块使用两个低维特征网格有效地建模固有高维音…
推荐文章