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

7.7 KiB
Raw Blame History

Promise

进程/线程

进程: 独立的工厂, 相互隔离

线程: 共享工厂资源的工人, 既可以协作, 也可能互相抢资源

特性 进程 线程
资源分配 独立的内存空间 共享进程的内存空间
独立性 完全独立,互不影响 共享资源,可能相互影响
通信方式 通过管道、消息队列等 直接共享内存
开销 创建和销毁开销较大 创建和销毁开销较小
适用场景 需要完全隔离的任务(如不同程序) 需要高效协作的任务(如多任务处理)

同步/异步

同步: 自上而下一行行执行

缺点: 会出现阻塞的情况, 一行代码运行慢会阻碍后面代码的执行

解决方法: ava/python: 多线程nodejs: 异步

异步: 一段代码执行不会影响后面的代码

缺点: 无法通过return来设置返回值

解决方法: 回调函数

新问题: 回调地狱, 可读性差, 难调试

解决方法: promise : 一个特殊的容器, 用来存储异步调用的数据

promise

创建 Promise

/**
* 创建Promise时, 构造函数需要一个函数作为参数
* Promise构造函数的回调函数,会在创建Promise时执行,执行时有两个参数传递进去: resolve, reject
*   resolve, reject, 也是两个函数, 通过这两个函数可以向Promise存储数据
*       resolve 在执行正常时存储数据
*       reject 在执行错误时存储数据
*    读取数据:
*        通过Promise实例的then方法来获取数据
*            then需要两个回调函数作为参数
*                通过resolve存储的数据会通过第一个返回
*                通过reject或者出现异常,会通过第二个返回
*/
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 的三种状态

/**
* 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, 则调用第二个回调函数来返回数据
*/
// 这两种写法是等价的
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

/**
 * promise
 *    then()
 *    catch()
 *    finally()
 *    这三个方法都是返回一个新的promise
 *      then() catch() 返回的Promise会存储回调函数的返回值
 *      finally() 的返回值, 不会存储到新的Promise
 */
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 的链式调用

/**
 * 链式调用,读取的是上一步的执行结果
 * 如果上一步不是想要的, 则跳过当前的方法
 */
/**
 * 当promise链式调用中,如果没有catch接收错误, 就会向外抛出
 * throw new Error()可以主动抛出异常
 * catch一般在最后写
 */
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 的静态方法

/**
 * 静态方法
 *  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接收
 */
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))