跟简单却又晦涩的 Promise 说 Hello

一、前言

  1. 我不知大家是如何接触到的 Promise, 我想可能是 Axios? 可能是对异步方法的封装?可能是对 Vue 中方法的封装?对 React 中方法的封装?
  2. 我记得我当时还是只会一些 ES5 语法小白的时候,为了看懂别人写的代码,大量恶补 ES6 的新语法,与此同时我接触到了可爱又可恨的 Promise,为了学会并掌握 Promise,我看了大量的文章,很大一部分的文章都是使用 setTimeout() 进行模拟异步流程,有的时候会陷入到:哦,我懂了 → 这是为啥呢? → 查看文章学习 → 哦,我又懂了 → What?的死循环中。
  3. OMG!对于当时的我来说就是噩梦,因为当时的我每打开一篇文章,啊!又是 setTimeout() 模拟的 Promise(),因为在真实场景中都是发送的Ajax请求,使用setTimeout() 模拟的这种根本不能真实体会到发送ajax的这种感觉。
  4. 这篇我将携手我们的小助理 ChatGPT从 Prmose 的 基本概念 → Prmose 的 基本原理 → Promise 的使用 Tips → 使用 Promise 封装原生 XMLHttpRequest → 使用 Promise 封装微信小程序中的 request 接口 → 使用 Promise 封装原生工具 ,使用 Express 快速搭建后端接口数据,一站式帮助大家理解 Promise 。

提升通道:这里我强烈推荐尚硅谷的 张晓飞 老师的 《手写Pomise课程》,我并没有做什么推广,只是手写完成之后,感觉茅塞顿开,你可能会在之后忘记具体的实现,但你会对 Promise 的基本原理会记忆犹新 !! 话不多说直接开整。

二、Promise 的基本概念

Promise的概念我们可以从多方面搜索一下

维基百科
请添加图片描述

ChatGPT
请添加图片描述

MDN

在这里插入图片描述

从多方搜索很显然显然发现 pending、fulfilled、rejected
三个状态总是可以映入我们的眼帘,之后我们会从这三个关键状态说起,从维基百科可以发现,Promise 是在 并发编程语言中都是存在的,显而易见如果你学懂了 JavaScript 中的 Promise , 那对于 Java 中的 Future,Netty 中的Promise 也就不在话下了,概念基本都是相同的,可能在实现上有所差别罢了!

OK, 我们了解了一下 Promise 中的基本概念后,即将进入我们的正题,如果感觉还不够详细的话,大家可以自行进行搜索了解,本人推荐使用 NewBings 进行搜索,他可以给你精确的答案。

三、Promise 的基本原理

1、 前置知识

在这里我不会直接去讲解 Promise 的基本原理,因为 Promise的原理在网络上随便一搜索就可以得到成千上万的答案,直接带大家学习可能大家也不会深入理解。

能看到这里的家人们一定对 DOM 的事件回调,以及 setTimeout() 的事件回调,还有大家常用的 AJAX发送请求的事件回调,可是大家知道他的调用流程吗?

在这里,我给大家提供了一张执行图,本人艺术细胞也不是很高,画图水平也就那样,将就着看看,目的是让大家能够理解。

在这里插入图片描述
刚看到这个图的时候,一定会感觉到十分的混乱,接下来由我一一讲解。

首先是图的橙色部分:这部分是JavaScript 的执行引擎部分,学过 三件套的都应该知道,Web浏览器的三大核心 DOM,BOM, JavaScript 执行引擎, 执行引擎部分主要包括堆、函数的调用栈等信息,堆主要存储一些对象信息,栈则是函数执行时的容器。

红色部分: Web页面的API的管理模块主要负责异步方法的处理。

蓝色部分:是宏队列的执行流程,如果Main线程中函数有宏任务,则会将宏任务放到宏队列中。

绿色部分:是微队列的执行流程,如果Main线程中函数有微任务,则会将微任务放到微队列中。

还有一个十分重要的点就是事件循环机制,接下来将会为大家讲解。

在这里我们根据一个简单的例子来理解一下:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><button id="click-button">单击按钮</button><script>// 获取 button DOM 对象let button = document.getElementById('click-button')// 定义函数 function-oneconst functionOne = () => {button.addEventListener('click', () => {console.log('按钮被点击了')})console.log('functionOne 执行完成')}// 定义函数 function-twoconst functionTwo = () => {setTimeout(() => {console.log('setTimeout 执行完成')}, 1000)console.log('functionTwo 执行完成')}// 执行functionOne()functionOne()// 执行functionTwo()functionTwo()console.log('主函数执行完成')</script>
</body></html>

我给大家提供了一段简单的代码,大家试着运行理解一下

大家可以把 script 标签中的内容简单理解为 Main 线程,其实这里的理解不是很准确的,Main线程的功能不止这些。首先

→获取 button 对象
→ 定义 functionOne()
→ 定义 functionTwo()
→ 执行functionOne() (将 click 监听任务放到宏队列)
→ 执行 functionTwo()(将 setTimeOut任务 放到宏队列)
→ 主函数执行完成
→ setTimeOut 函数时间到触发回调执行
→ 如果你点击了按钮执行按钮回调执行事件

这里有一个很重要的点:宏队列和微队列的执行一定在 Main 线程执行完成后才会去执行。可以有些人会有疑问如果我把 setTimeout 的事件设置为0 会比 console.log(‘主函数执行完成’) 先执行吗? No, 不会的,它一定会被放到宏队列中去,等 Main 函数执行完成才会去执行。

Ok,基础的知识讲解完成,大家对宏队列也有了一定的理解,那么开始我们的重点: Promise

2、Promise 基础知识

当我们不知道如何下手的时候,我们可以 寻求 AI 的帮助,让他帮忙写一个案例:

在这里插入图片描述
大家还记得 在第二部分 提到的三个状态和微队列吗?pending、fulfilled、rejected 和前置条件中的图,那我们就从这个案例说起,当我们 new Promise() 时,该 Promise 处于 pending 状态也就是代办状态, JavaScript 执行引擎会将该 Promise 放入到APIs管理模块中去进行管理,当状态发生改变时,则会将 Promise 的回调函数放入到微队列中去,那我们如何改变状态?以及如何给Promise 指定回调呢?在 new Promise对象时,不要忽略了两个参数 resolve 和 reject,这两个参数其实是两个函数也就是通过这两个函数来改变 Promise 的状态;那我们如何指定回调函数呢?大家可以通过 ChatGPT 给我们生成的案例的第二条, 通过 then 和 catch 指定正确和错误的回调。

下面我将通过一个例子来带大家进行理解,大家可以创建一个 HTML 文件尝试多次运行:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title> the start of promise </title>
</head><body><script>// 创建新的 Promiselet promise = new Promise((resolve, reject) => {let number = Math.random()// 根据随机数的大小修改 Promise 的状态if (number < 0.5) {resolve({ code: 200, message: '成功', data: number })} else {reject({ code: 500, message: '失败', data: number })}})// 指定 成功的回调 和 失败的回调promise.then((successResult) => {console.log('success result : ', successResult)}).catch((failResult) => {console.log('fail result : ', failResult)})</script>
</body>
</html>

通过上面这个案例可以看出,在 Promise 中使用 resolve 函数 修改 Promise 的状态为 fulfilled 状态也就是成功状态,并且通过resolve 将成功的结果发送给了 then 回调函数,同理可以看出 Promise 也可以通过 reject 函数将失败的结果发送给了 catch 回调函数。

注意点在 Promise 中 resolve 和 reject 中二者只能执行其一,只要二者执行其一,就会触发微队列,进行事件回调。

3、细节分析 Promise 在微队列的执行

如果没有宏队列的任务,只有微队列的任务,那么微队列和宏队列的执行其实是大同小异的。只有我们去试着分析既有宏队列又有微队列的任务时,才能真正的理解,接下来我将会写一个比较复杂的调用流程(微任务使用 Promise,宏任务使用 setTimeout),试着和大家一起分析一下,话不多说直接上代码:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>细节分析 Promise</title>
</head><body><script>console.log("主函数开始执行")// 宏任务①setTimeout(() => {console.log("宏任务①, 回调执行")}, 0)// 微任务①new Promise((resolve, reject) => {resolve("成功")}).then(() => {console.log('微任务①, 回调执行')})// 宏任务②setTimeout(() => {console.log("宏任务②, 回调执行")// 创建微任务②new Promise((resolve, reject) => {resolve("成功")}).then(() => {console.log('微任务②, 回调执行')})}, 0)// 微任务③new Promise((resolve, reject) => {resolve("成功")}).then(() => {console.log('微任务③, 回调执行')})console.log("主函数结束执行")</script>
</body></html>

大家想到了执行的过程了吗?
在这里插入图片描述
接下来我将带大家一起分析执行流程:用这个 【】 表示宏队列,用 [] 表示微队列

→ 毫无疑问 首先打印 主函数开始执行
→ 将宏任务①放到宏队列中 【①】
→ 将微任务①放到微队列中 [①]
→ 将宏任务②放到宏队列中 【①,②】,此时还并没有创建微任务②
→将微任务③放到微队列中 [①,③]
→打印 主函数结束执行 主函数执行结束
由于微任务和宏任务都有任务,则先执行微任务, 打印 微任务①, 回调执行
微任务③, 回调执行 微任务队列变为 [ ]
执行宏任务 打印 宏任务①, 回调执行;打印 宏任务② 回调执行;大家还记得宏任务一种有一个微任务②吗?这是会将微任务②加入到微任务队列中 [②]
打印微任务②, 回调执行

其实大家有没有注意到一点,我把 setTimeout 的时间设置为了 0,大家有没有想过我在发送网络请求的时候会有一定的延时。上面的案例只是演示了最理想的情况下,如果我们把宏任务 ① 的倒计时时间设置为 10000 呢? 他一定是在最后执行的,大家没有记得在我画的那张图中,有一个 APIs 管理模块,其实倒计时的过程是在那里面执行的,只有执行完毕后才会将回调放到宏任务队列中的。Promise 也是相同的,我在发送网络请求的时候 Promise 状态为 pending 的其实是在 APIs 管理中执行的,之后调用了 reject 或者 resolve 函数,才会将回调放到微队列中。

4、EventLoop 事件循环

大家有没有想过我们为什么在注册了 DOM 点击事件之后,无论我们何时点击 DOM,APIs 管理模块将其回调 Push 到宏任务队列中,都可以触发该事件,其实这就是事件循环机制的功劳,他会一个周期一个周期轮询监听,如果在微队列和宏队列中有可执行的任务的任务回调,它就会将该任务的回调读取到 Main 线程中进行执行。

5、微队列和宏队列 微任务与宏任务 小总结

  1. 宏任务和微任务都是异步任务,只是JavaScript 在宏队列和微队列中读取回调函数到主线程的任务顺序不同,在读取每个宏任务之前会读取所有的微任务。
  2. JavaScript 中用来存储待执行回调函数的队列包含两个不同的队列:宏队列和微队列
  3. 宏队列:用来保存待执行的宏任务(回调)比如:定时器回调 / ajax回调
  4. 微队列:用来保存待执行的微任务(回调)比如:Promise 回调
  5. 重点:每次取出宏任务到主线程之前,则会将微任务一一取出到主线程执行。

四、Promise 的使用 Tips

1、.then 和 .catch 的返回结果为 Promise

首先我们把一开始 Promise 的案例拿过来, 我们用 returnPromise 来接收.then 或者 .catch的结果

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Promise .then .catch</title>
</head>
<body><script>// 首先我们, 创建新的 Promiselet promise = new Promise((resolve, reject) => {let number = Math.random()// 根据随机数的大小修改 Promise 的状态if (number < 0.5) {resolve({ code: 200, message: '成功', data: number })} else {reject({ code: 500, message: '失败', data: number })}})// 返回的 Promiselet returnPromise = promise.then((successResult) => {console.log('success result : ', successResult)}).catch((failResult) => {console.log('fail result : ', failResult)})console.log(`returnPromise`, returnPromise)</script>
</body>
</html>

通过打印 returnPromise 发现确实无论是.catch 和 .then 的返回值都是 Promise,大家想一个问题,如果返回的是一个 Promise 我们就可以一直 .then 下去。

我们可以将上面的代码块,进行改进。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Promise .then .catch</title>
</head>
<body><script>// 首先我们, 创建新的 Promisenew Promise((resolve, reject) => {let number = Math.random()// 根据随机数的大小修改 Promise 的状态if (number < 0.5) {resolve({ code: 200, message: '成功', data: number })} else {reject({ code: 500, message: '失败', data: number })}}).then((successResult) => {console.log('then1 ----> success result : ', successResult)}).then((result) => {console.log('then2 ----> result : ', result)}).catch((failResult) => {// 在这里可以直接返回一个空的Promise,来阻断链的调用// return new Promise(() => {})console.log('fail result : ', failResult)}).then((result) => {console.log('final then ---> result : ', result)}).catch((result) => {console.log('final catch ---> result : ', result)})</script>
</body>
</html>

如果成功了 会执行
在这里插入图片描述
如果失败了会执行
在这里插入图片描述
这里大家可以观察到:无论是执行失败还是都会执行 final then —→ result : undefined

这是为什么呢?大家有没有记得我刚才说的,.catch 和 .then 一定会返回一个 Promise ,如果我们没有返回值,则会默认返回一个成功的 Promise ,并且其携带的值为 undefined。

同理也可以得到,final catch → result 永远都不会执行,因为 如果出现了异常,则会被第一个 catch 所捕获,而第一个 catch 一定返回一个成功的 Promise.

可能会有人疑问为什么我中间的 catch 已经捕获到异常了,为什么还要成功的走下面的流程呢?

其实这就是 Promise 的一个规则,如果你想 catch 后不行继续执行下面的流程,则直接返回一个 pending 状态的 Promise ,来阻断 Promise 链的调用,这也就是所说的终止 Promise, 这个点还是十分的关键的,请大家牢记。为什么可以用来阻断 Promise 呢? 大家想想,如果 Promise 没有改变状态他的回调是永远都不会放到异步队列中去的,所以永远都不会执行。

2、Promise 的原型方法

在 JS 中一开始是没有像 Java 那种继承体系,他只有通过这种 原型链的方式 模拟继承体系,也不能说模拟吧,每种语言有每种语言的特点。JavaScript 可以在对象的原型上定义一些方法,可以供 new 出来的对象公共使用。

比如之前我们所用的 catch()、then() 都是原型链上的方法。

还有两个十分常用的 Promise.resolve() 和 Promise.reject() 大家看这两个方式是不是与 new Promise()的时,与其中的回调函数相同。是的其实他们的作用是基本相同的,但是这两个方法可以在不 new Promise 的情况下直接返回 一个成功或者失败状态的 Promise

还记不记得上一个模块我们所说的 .then() 和 .catch() 的回调返回一个 Promise 实例对象, 如果没有返回值,则返回一个成功的且内容为 undefined 的回调,其实这里可以直接使用 Promise.resolve() 或者 Promise.reject() 返回一个成功或者失败的回调。例如

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Promise.reject()和Promise.resolve()</title>
</head>
<body><script>new Promise((resolve, reject) => {let number = Math.random()// 根据随机数的大小修改 Promise 的状态if (number < 0.5) {resolve({ code: 200, message: '成功', data: number })} else {reject({ code: 500, message: '失败', data: number })}}).then((result) => {return Promise.reject('fail')// 或者 return Promise.resolve('success')}).catch((err) => {console.log('err', err)})</script></body>
</html>

还有一种情况:如果我们直接返回一个具体的值相当于返回成功的 Promise 并且携带成功的值相当于 Promise.resolve(value),如果 throw 一个异常相当于返回一个失败的 Promise 相当于使用 Promise.reject(value)

3、解决回调地狱?

解决回调地狱是怎么一回事呢?比如我现在要发送两个请求,如果第二个请求需要第一个请求的参数,那么第二个请求就必须要在第一个请求结束后,第二个请求拿到第一个请求的参数,才可以发送第二个请求。

我刚开始写的时候是这样的:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Promise .then .catch</title>
</head>
<body><script>// 模拟用户发送const getStudentMessage = () => {// 模拟发送网络请求,模拟获取学生信息return Promise.resolve({id:`001`, name:'Dylan', age:20})}const getSchoolByStudent = (studentId) => {// 模拟发送网络请求,根据学生id获取 学生的学校信息return Promise.resolve({id:'001', schoolName:'xxxxxx'})}// 需求查询用户信息的学校信息const queryStudentSchoolMessage = () => {getStudentMessage().then((student) => {console.log('学生信息:', student);getSchoolByStudent(student.id).then((school) => {console.log("学校信息: ",school)})})}// 调用执行queryStudentSchoolMessage()</script>
</body>
</html>

其实上面的写法并没有解决回调地狱的问题,他只不过是 Promise 的回调地狱罢了, 我一开始写的时候,也很纳闷,这不还是回调地狱吗?

那我们该如何解决回调地狱问题呢? 还记得我们说的 .then() 返回 Promise 吗,对了我们就是用这个。

// 需求查询用户信息的学校信息
const queryStudentSchoolMessage = () => {getStudentMessage().then((student) => {console.log('学生信息:', student);return getSchoolByStudent(student.id)}).then((school) => {console.log('学校信息:',school);})
}

4、.catch的传透性

穿透性 比较好理解,就是我们可以写很多个 .then() 方法,在最终统一处理异常 也就是 .catch() ,这样的话,无论在那个 .then 中出现了异常,都会透传到 .catch()

大家还记得 在 .then() 和 .catch() 中,只要抛出异常,就会返回 失败的 Promise,就会透传到最终的 .catch(),这一点大家不要忘记。

5、终止 Promise

终止 Promise 我们上面已经说过了,就是可以直接返回一个 pending 状态的 Promise 即 new Promise(() ⇒{})

6、async 和 await

首先我们从字面意思上理解 async 是同步的意思,而 await 是 等待的意思,有人会问了,我们现在不是使用异步吗,为什么还需要同步呢? 其实不然,有的时候就像我们刚才举的那个例子,两个异步方法就是需要同步执行,二异步是无法控制执行顺序的,只有通过回调地狱或者 Promise.then() 方式控制其顺序,与其回调地狱,与其连续.then JavaScript 直接推出的新的语法糖 async 和 await,供大家使用。那我们该如何使用呢,我们还是以上面的例子为例进行改写:

const queryStudentSchoolMessage = async () => {const student = await getStudentMessage()console.log('学生信息:', student);const school = await getSchoolByStudent(student.id)console.log('学校信息:',school);
}

有没有柳暗花明又一村的感觉, 那这是为什么呢?

其实在 Promise 前面使用 await 相当于进行了 .then 其拿到的结果就是 .then 回调中的参数,也就是成功的值,如果使用 await 则会将该方法转化为同步的方法,如果没有拿到返回的值,则会等待,无论是等待 10 秒 还是 20 秒,这样一来就起到了同步的作用。

还有十分重要的一点,await 必须在 async 声明的函数中使用,故名思议这个函数是同步的,这里的函数通过不是说有了 async 就是所有的内容都同步,而是必须结合使用 await 来控制同步

接下来我将带大家写一些基本的案例,来强化 Promise 的使用,我们可以借助 ChatGPT 帮助我们轻松的实现,如果你掌握了 Promise ,你的编码水平一定会更胜一筹。

五、使用 Promise 封装原生 XMLHttpRequest

1. 封装 XMLHttpRequest

大家应该使用过 Axios ,其实就是使用 Promise 对 原生 XMLHttpRequest 的封装,如果大家能这个案例学会,其实对 Axios 的理解也就大差不差了。

下面我们根据这段代码来理解一下:

在这里插入图片描述

OK, 上来就可以看到,直接返回 Promise, 还记不记得我上文写的 获取学生的信息,其实我相当于直接返回了成功的 Promise 并且携带学生的信息。这里是相同的。

大家注意一下 onreadystatechange 回调函数,其实就是如果成功(200~300),则将 Promise 设置为成功 ,如果失败,将 Promise 设置为失败状态

onerror 方法 如果请求过程中出现异常,则直接返回失败结果。

2、搭建 接口服务器

你可以根据你喜欢的语言搭建一些请求的接口比如 Java、Node.js、 go、c 等等,这里我们借助 ChatCPT 可以快速搭建后端路由接口。
在这里插入图片描述

我们借助 AI 工具有的时候还是很容易搭建出我们想要的结果的,只要我们进行微调即可,既然他能返回 Hello,World,那么我们就可以返回对象,数组。

六、使用 Promise 封装 微信小程序 中的 Request 接口

如果做过微信小程序的开发你一定会知道,wx.request() 是 真 xx 难用,其实我们完全可以使用 Promise 进行封装,来统一接口的处理。

const request(url, method, data) => {return new Promise((resolve, reject) => {wx.request({url: url,method: method,data: data,header:headersuccess: (res) => {resolve(res.data);},fail: (error) => {reject(error);}})})
}

在真实的业务需求中你可以进行封装的完善。比如统一异常处理等等。

七、使用 Promise 封装原生工具

我们可以直接用来封装 wx.modal() 简化我们的操作,我们聚焦于业务中,而不需要,考虑这些方法的使用上。

export const modal = (content = '是否确认操作', title = '提示') => {return new Promise((resolve) => {wx.showModal({title,content,success: ({confirm, cancel}) => {if (confirm) {resolve(true)} else if (cancel) {resolve(false)}}})})
}

我们也可以封装一些 Axios 请求,使我们的业务逻辑更加的清晰。

login({ commit }, userInfo) {const { username, password } = userInforeturn new Promise((resolve, reject) => {login({username, password }).then(response => {let data = responseif(data.success){commit('SET_TOKEN', '库里的球衣')resolve()}else{reject(data)}}).catch(error => {reject(error)})})},

八、总结

  1. 如果我们真正掌握了 Promise , Promise 在前端领域是无处不在的,毕竟要发送网络请求嘛,有很多方法将其使用 Promise 封装后,在调用层面会显得格外的清晰明了。
  2. 通过全文可以看出,我有更多的点都是借助 AI 工具去生成的,这样可以帮助我们快速大家出我们想要的环境,使我们 聚焦于 某一领域。
  3. 如果有问题,可以在评论区及时提出,我们一同改进,我的理解也只是冰山一角,欢迎大家一同讨论。

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

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

相关文章

在win10电脑上搭建python环境下的本地AI绘画工具Stable Diffusion

随着Chatgpt的横空出世&#xff0c;人工智能受到了前所没有的热棒&#xff0c;AI绘画也进入大众的视野。 Stable Diffusion是一种可以部署在本地环境上运行的人工智能绘画工具&#xff0c;图形运算主要用到的是显卡的GPU性能&#xff0c;因此最好有至少4G显存的显卡。 Stable…

chatgpt赋能python:Python画图写名字——提升SEO的绝佳选择

Python画图写名字——提升SEO的绝佳选择 随着互联网的发展&#xff0c;SEO&#xff08;搜索引擎优化&#xff09;变得越来越重要&#xff0c;而优秀的内容和图片对SEO排名的提升起着非常重要的作用。Python作为一种高效的编程语言&#xff0c;也是SEO方面的新宠&#xff0c;因…

Qt6教程之三(6) 界面自绘与绘图类

据博主所知&#xff0c;Qt的绘图技术目前分为三大阵营&#xff0c;分别是&#xff1a; 一&#xff0c;基于QWidget的界面自绘制&#xff0c;这种方式纯粹为纯代码绘制&#xff0c;随着绘制图形量的不断增加&#xff0c;会导致其难以管理和性能不佳&#xff1b; 二&#xff0c…

HighCharts实现3D不同高度圆环图、3D饼图

最近做可视化比较多&#xff0c;就常用的图表类型做了一下总结。 因为做可视化的图表代码量非常大&#xff0c;所以会把echarts图表单独抽离出来&#xff0c;封装成一个组件&#xff0c;也可以复用&#xff0c;所以这里我直接把封装的组件直接放在这里&#xff0c;是可以直接拿…

直播合辑 | 微软ATP与您相约100场公益演讲

&#xff08;本文阅读时间&#xff1a;5 分钟&#xff09; Public100已历经了近一年的春夏秋冬&#xff0c;截止目前我们一共举办33场公益直播&#xff0c;由微软及合作伙伴中从事 AI 相关工作的工程师、产品经理、市场总监、运营经理等各类专家和学者&#xff0c;分享自己在学…

微信春节大数据出炉:《三体》阅读量第一 ;曝iOS 17应用商店将向第三方开放;斯坦福大学推出DetectGPT|极客头条...

「极客头条」—— 技术人员的新闻圈&#xff01; CSDN 的读者朋友们早上好哇&#xff0c;「极客头条」来啦&#xff0c;快来看今天都有哪些值得我们技术人关注的重要新闻吧。 整理 | 梦依丹 出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09; 一分钟速览新闻点&#…

ChatGPT 串接 Firebase,實現上下文歷史紀錄

ChatGPT 串接 Firebase&#xff0c;實現上下文歷史紀錄 在使用 ChatGPT API 時&#xff0c;因為 API 本身是「一次性」&#xff0c;無法儲存聊天的歷史紀錄&#xff0c;這也衍生了「無法串聯上下文」的問題&#xff0c;不過如果將 ChatGPT 串連 Firebase 的 Realtime database…

ChatGPT:我围观了量子位MEET2023智能未来大会,还当了一回课代表

编辑部 ChatGPT 发自 凹非寺量子位 | 公众号 QbitAI 什么是“MEET2023智能未来大会”&#xff1f; 大会上来了哪些重磅嘉宾&#xff1f; 他们在大会上探讨了什么主题&#xff1f; 没错&#xff01;ChatGPT也参与了今年的大会&#xff0c;作为AI代表与人类嘉宾们一起回顾这一年来…

LM详解 GPT3,GPT2, GPT1 论文译读

LM详解 GPT3&#xff0c;GPT2, GPT1 论文译读 T5&#xff0c;Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer&#xff0c;2019 arxiv https://arxiv.org/abs/1910.10683 中译 https://zhuanlan.zhihu.com/p/89719631 讨论 如何评价 Goo…

chatgpt赋能python:Python提取扫描版PDF:一篇SEO文章

Python提取扫描版PDF&#xff1a;一篇SEO文章 Python在数据科学、自然语言处理、机器学习等领域中广泛应用。今天我们将关注Python的另一个应用&#xff1a;提取扫描版PDF。本文介绍了如何使用Python提取文本以及搜索引擎优化&#xff08;SEO&#xff09;的最佳实践。 提取扫…

Python3,5行代码,Chatxxx能对PDF文件进行旋转、提取、合并等一系列操作,看了这篇,80岁老奶奶走路都不扶墙了。

ChatPDF的妙用 1、引言2、代码实战2.1 原理2.2 安装2.2 示例2.2.1 创建PDF文件2.2.2 旋转PDF文件2.2.3 拆分PDF文件2.2.4 合并PDF文件2.2.5 提取PDF文件内容 3、总结 1、引言 小屌丝&#xff1a;鱼哥&#xff0c;最近干啥了&#xff1f; 小鱼&#xff1a;最近&#xff1f; 你指…

chatgpt赋能python:Python实现多关键词搜索PDF文件

Python实现多关键词搜索PDF文件 概述 在今天的数字化社会中&#xff0c;很多信息都以数字化的形式存储在PDF文件中。这让我们在搜索特定信息时面临很多挑战&#xff0c;特别是当我们需要同时搜索多个PDF文件并集中检索这些文件时。 在这篇文章中&#xff0c;我们将介绍如何使…

零代码编程:用ChatGPT将PDF文件的表格批量转为Excel表格

电脑中有几百个PDF文件&#xff0c;文件内容格式一致&#xff0c;每个PDF文件第一页是一个表格。想把这几百个PDF文件里面的表格都提取出来&#xff0c;转为excel表&#xff0c;该怎么办&#xff1f; 打开ChatGPT&#xff08;一定要用GPT4&#xff0c;编程能力很强。相比之下&a…

chatgpt赋能python:Python抓取PDF内容:一个全面的指南

Python 抓取 PDF 内容&#xff1a;一个全面的指南 引言 Python 作为一种广泛使用的编程语言&#xff0c;已经拥有了许多应用功能。其中之一是抓取 PDF 文件的内容。 PDF 文件在今天的数字化世界中使用广泛&#xff0c;使得从 PDF 文件中提取内容变得尤其重要&#xff0c;对于…

ChatGPT-4模型读取PDF/网页链接实测结果!

联网和插件功能使用 直接在设置里面&#xff0c;把这两个开关开起来 联网功能&#xff1a; 3.5不会的东西是不会自动联网搜索的&#xff0c;Plus4.0可以进行联网搜索答案 插件功能&#xff1a; 首先在Settings里面把Plugins进行安装&#xff0c;选中要安装的插件&#xff0c;直…

a16z深度分析:AI 将创造哪些新的游戏玩法?

来源/a16z 编译/Nick 早期关于游戏中的生成式 AI 革命的讨论主要集中在 AI 工具如何提高游戏创作者的效率&#xff0c;使得游戏的制作速度比以前更快、规模更大。从长远来看&#xff0c;我们认为&#xff0c;AI 不仅能改变创造游戏的方式&#xff0c;还能改变游戏本身的性质。 …

ChatGPT对金融业将产生哪些影响?

黄浦区金融办 2023-05-22 02:30 发表于上海 近期人机互动模型ChatGPT进入应用领域&#xff0c;意味着人工智能的发展达到了新高地。那么&#xff0c;人工智能在金融领域的应用与未来发展趋势如何&#xff1f;会给金融机构带来哪些挑战&#xff1f;日前&#xff0c;《金融时报》…

OpManager 实时网络监控

网络是全球企业背后的基础。它在为您的员工提供行政服务以及为各大洲的客户提供服务方面发挥着关键作用。网络可帮助您将信息保存在一个集中位置 - 需要和限制所有其他入站请求的人员可以访问。那么&#xff0c;您如何提供持续的一流最终用户体验并维护快速发展的网络呢&#x…

使用 LangChain、Pinecone 和 LLM(如 GPT-4 和 ChatGPT)构建基于文档的问答系统

目录 一、简介 二、为什么语义搜索GPT问答比微调GPT更好&#xff1f; 2.1、更广泛的知识覆盖&#xff1a; 2.2、特定于上下文的答案&#xff1a; 2.3、适应性 2.4、更好地处理模糊查询 三、LangChain 模块 四、设置环境 五、加载文档 六、分割文档 七、使用 OpenAI 嵌入…

ChatGPT 启示录:AI 已经把人类逼退到了信仰和宗教的边界上了?

哲学的滑落 哲学之初&#xff0c;研究的对象是客观存在的物质实体&#xff0c;物体是不依赖于人们思想的东西。后来康德、叔本华等说物自体不可知&#xff0c;于是哲学家离开客体&#xff0c;转而研究人这一主体&#xff0c;研究人们内在感知到的表象世界。 到了维特根斯坦这里…