devStandard/docs/learning/3-js/2.4-Promise.md
2025-03-29 14:35:49 +08:00

272 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Promise
## 进程/线程
进程: 独立的工厂, 相互隔离
线程: 共享工厂资源的工人, 既可以协作, 也可能互相抢资源
| **特性** | **进程** | **线程** |
| -------- | ---------------- | ----------------- |
| **资源分配** | 独立的内存空间 | 共享进程的内存空间 |
| **独立性** | 完全独立,互不影响 | 共享资源,可能相互影响 |
| **通信方式** | 通过管道、消息队列等 | 直接共享内存 |
| **开销** | 创建和销毁开销较大 | 创建和销毁开销较小 |
| **适用场景** | 需要完全隔离的任务(如不同程序) | 需要高效协作的任务(如多任务处理) |
## 同步/异步
**同步:** 自上而下一行行执行
缺点: 会出现阻塞的情况, 一行代码运行慢会阻碍后面代码的执行
解决方法: ava/python: 多线程nodejs: 异步
**异步:** 一段代码执行不会影响后面的代码
缺点: 无法通过return来设置返回值
解决方法: 回调函数
新问题: 回调地狱, 可读性差, 难调试
解决方法: promise : 一个特殊的容器, 用来存储异步调用的数据
## promise
### 创建 Promise
```js
/**
* 创建Promise时, 构造函数需要一个函数作为参数
* Promise构造函数的回调函数,会在创建Promise时执行,执行时有两个参数传递进去: resolve, reject
* resolve, reject, 也是两个函数, 通过这两个函数可以向Promise存储数据
* resolve 在执行正常时存储数据
* reject 在执行错误时存储数据
* 读取数据:
* 通过Promise实例的then方法来获取数据
* then需要两个回调函数作为参数
* 通过resolve存储的数据会通过第一个返回
* 通过reject或者出现异常,会通过第二个返回
*/
```
```js
const mypromise = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('hello')
// reject('err')
},3000)
})
mypromise.then((result)=>{
console.log('resolve:',result)
},(reason)=>{
console.log('reject或者异常:',reason)
})
```
### Promise 的三种状态
```js
/**
* Promise中维护了两个隐藏的属性
* - PromiseResult: 存储数据
* - PromiseState: 存储状态(三种)
* - pending 正在进行
* - fulfilled 完成 通过resolve存储数据
* - rejected 拒绝 通过reject存储数据或者异常
* state只能修改一次, 修改后永远不会变
*
* 流程:
* 当Promise创建时, PromiseState初始值为pending
* 通过resolve存储数据时, PromiseState变为fulfilled, PromiseResult变为存储的数据
* 通过reject存储数据或者异常, PromiseState变为rejected, PromiseResult变为存储的数据或异常数据
* 当通过then读取数据, 相当于为Promise设置了回调函数
* 如果PromiseState为fulfilled, 则调用then第一个回调函数来返回数据
* 如果PromiseState为rejected, 则调用第二个回调函数来返回数据
*/
```
```js
// 这两种写法是等价的
const promise2 = new Promise((resolve,reject)=>{
resolve('hello')
})
// const promise2 = Promise.resolve('hello')
const promise3 = new Promise((resolve,reject)=>{
reject('err')
})
/**
* catch() 用法和then类似, 只需要一个回调函数作为参数
* catch() 只在Promise被拒绝时才执行, 相当于 then(null,reason=>{})
* 是用来专门处理Promise异常的方法
*/
promise3.catch((err)=>{
console.log(err)
})
/**
* finally() 无论正常或者异常,finally总会执行
* 但是finally的回调函数中不会接收到数据
* 一般用来写一些无论成功或失败总要执行的代码
*/
promise2.finally(()=>{
console.log('总会执行')
})
```
### then (), catch () 的返回也是 Promise
```js
/**
* promise
* then()
* catch()
* finally()
* 这三个方法都是返回一个新的promise
* then() catch() 返回的Promise会存储回调函数的返回值
* finally() 的返回值, 不会存储到新的Promise
*/
```
```js
const sum = (a, b) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(a + b)
}, 0)
})
}
const p2 = sum(1, 2).then()
console.log('p2:', p2)
const p3 = sum(1, 2).then(result => {
return result
})
console.log('p3:', p3)
sum(1, 2)
.then(result => {
return sum(result, 3)
})
.then(result => {
return sum(result, 4)
})
.then(result => {
console.log('链式调用:', result)
})
```
### Promise 的链式调用
```js
/**
* 链式调用,读取的是上一步的执行结果
* 如果上一步不是想要的, 则跳过当前的方法
*/
/**
* 当promise链式调用中,如果没有catch接收错误, 就会向外抛出
* throw new Error()可以主动抛出异常
* catch一般在最后写
*/
```
```js
const promise = new Promise((resolve, reject) => {
// resolve('hello')
reject('hello')
})
promise.then(result => {
console.log('读取第一个then', result)
return 'world'
}).catch(result=>{
// 没有错误,不执行
console.log("读取第一个catch", result)
return 'err'
}).then(result=>{
console.log('读取第二个then', result)
})
```
### Promise 的静态方法
```js
/**
* 静态方法
* Promise.resolve() 创建一个立即完成的Promise
* Promise.reject() 创建一个立即拒绝的Promise
* Promise.All() 参数是一个可迭代对象(数组),里面放Promise, 存储的是每个Promise的结果
* 返回的也是一个个Promise对象
* 数组只要有一个Promise拒绝, 就会出错
* Promise.allSettled() 参数是一个可迭代对象(数组),里面放Promise, 存储的是每个Promise的结果
* 无论成功失败都返回结果, 每个结果都放到一个对象里
* 成功: {status: 'fulfilled', value: 3}
* 失败:{status: 'rejected', reason: '出错了'}
* vscode 调试模式需要打断点才能在控制台看到内部数据
* Promise.race() 参数是一个可迭代对象(数组),里面放Promise, 存储的是最快完成的,不论成功失败
* Promise.any() 参数是一个可迭代对象(数组),里面放Promise, 存储的是最快完成的, 只存成功的
* 只有都发生错误, 才会抛出错误, 可以用catch接收
*/
```
```js
Promise.resolve(1).then(result => console.log(result))
Promise.reject(2).catch(err => console.log(err))
const sum = (a, b) => {
return new Promise(
resolve =>
setTimeout(() => {
resolve(a + b)
}),
3
)
}
// sum(1,2)
// sum(2,3)
// sum(3,4)
Promise.all([sum(1, 2), sum(2, 3), sum(3, 4)]).then(result => {
console.log(result)
})
Promise.all([sum(1, 2), sum(2, 3), Promise.reject('出错了'), sum(3, 4)])
.then(result => {
console.log(result)
})
.catch(err => {
console.log('all遇到拒绝:', err)
})
Promise.allSettled([sum(1, 2), sum(2, 3), Promise.reject('出错了'), sum(3, 4)]).then(result => {
console.log('allSettled:', result)
})
Promise.race([sum(1, 2), sum(2, 3), sum(3, 4), Promise.resolve('立即完成')]).then(result => {
console.log('rece返回最快的:', result)
})
Promise.race([sum(1, 2), sum(2, 3), sum(3, 4), Promise.reject('立即拒绝')]).then(result => {
console.log('race返回最快的:', result)
}).catch(err=>console.log('race遇到拒绝的:',err))
Promise.any([sum(1, 2), sum(2, 3), sum(3, 4)]).then(result => {
console.log('any返回最快的:', result)
})
Promise.any([sum(1,2),Promise.reject('拒绝2')]).then(result => {
console.log('any返回最快的:', result)
}).catch(err=>console.log('any拒绝了的',err))
Promise.any([Promise.reject('拒绝1'),Promise.reject('拒绝2')]).then(result => {
console.log('any返回最快的:', result)
}).catch(err=>console.log('any都拒绝了',err))
```