# 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)) ```