# promise **Repository Path**: yushi5344/promise ## Basic Information - **Project Name**: promise - **Description**: Promise简单实现 - **Primary Language**: JavaScript - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-09-12 - **Last Updated**: 2022-05-31 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # promise ## Promise 的理解 1. Promise是什么? - 抽象表达 - Promise是一门新的技术 - Promise是JS中进行异步编程的新解决方案 - 具体表达 - 语法上: Promise是一个构造函数 - 功能上: Promise对象用来封装一个异步操作并可以获取其成功/失败的值. 2. 为什么要用Promise? - 指定回调函数的方式更加灵活 - 旧的: 必须在启动异步任务前指定 - promise: 启动异步任务=>返回promise对象=>给promise对象绑定回调函数 - 支持链式调用,解决回调地狱 - 什么是回调地狱: 回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调的执行条件 ![](./static/回调地狱.jpg) - 缺点: 不方便阅读,不便于异常处理 - 解决方案 :promise 3. Promise 的状态改变 - 状态指的是Promise实例对象中的一个属性 PromiseState - 初始状态 pending - 成功状态 resolved /fulfilled - 失败状态 rejected 只有这两种状态,并且一个promise对象状态只能改变一次. 4. Promise 对象的值 - 实例对象中的另一个属性, PromiseResult - 保存着对象[成功/失败]的值 resolve/reject 5. Promsie 工作流程 ![](./static/promise流程.png) ## Promise的使用 1. Promise构造函数 `Promise(executor){}` - `executor` 执行器(resolve,reject)={} - `resolve函数`: 内部定义成功时调用的函数 value={} - `reject函数`: 内部定义失败时调用的函数 reason={} - 说明: executor会在promise内部立即同步调用,异步操作在执行器中执行 2. Promise.prototype.then方法 `(onResolved,onRejcted)=>{}` - `onResolved` 成功的回调函数 value={} - `onRejected` 失败的回调函数 reason={} - 说明: 指定用于得到成功value的成功回调和用于失败reason的失败回调返回一个新的promise对象 3. Promise.prototype.catch (onRejected)=>{} - 失败时的回调函数 - then的语法糖,等同于 (undefined,onRejected)={} 4. Promise.resolve (value)=>{} - value 成的数据或者promise对象 - 返回一个成功/失败的promise对象 5. Promise.reject (reason)=>{} - resson 失败的原因 - 返回一个失败的promise对象 6. Promise.all (promises)=>{} - promises: 包含n个promise的数组 - 返回一个新的promise只有所有的promise都成功才成功,只要有一个失败,就直接失败 7. Promise.race (promises)=>{} - promises 包含n个promise的数组 - 返回一个新的promise,第一个完成的promise的结果就是最终的结果 8. Promise.any (promises)=>{} - promises: 包含n个promise的数组 - 返回一个新的promise,只要有一个成功,就返回一个成功的promise ## Promise 的几个关键问题 1. 如何改变promise状态 - resolve 将pending改为fulfilled - reject 将pending改为rejected - 抛出异常 如果当前状态为pending,就会变为rejected 2. 一个promise指定多个成功/失败的回调,都会调用吗 当promise状态改变时,都会调用. 3. 改变promise状态和指定回调谁先谁后 - 都有可能,正常状态下是先指定回调然后再改变状态,但也可以先改变状态,再指定回调 - 如何先改变状态,再指定回调 - 在执行器中直接调用resolve()/reject() - 延迟更长时间调用then - 什么时候才能得到数据 - 如果先指定的回调,则当状态发生改变时,回调函数就会调用,得到数据 - 如果先改变的状态,当指定回调时,回调函数就会调用,得到数据 4. promise.then返回的新promise的结果状态由什么决定 - 如果抛出异常,新promise变为rejected ,reason为抛出的异常 - 如果返回的是非promise的任意值,新promise变为resolved,value为返回的值 - 如果返回的是另一个新的promise,此promise的结果就是成为新的promise的结果 5. promise如何串联多个操作任务 - promise的then返回一个新的promise,可以开成then的链式调用 - 通过then的链式调用串联多个同步/异步任务 6. Promise异常穿透 - 当promise的then链式调用时,可以在最后指定失败的回调 - 当前面的任何操作出了异常,就会传到最后失败的回调中处理 7. 如何中断promise链 - 当使用promiSee的then链式调用时,在中间中断,不再调用后面的回调函数 - 办法 在回调函数中返回一个pending状态的promise对象 ## 自定义Promise 1. 构造函数的实现 ```javascript class Promise{ constructor(executor) { this.PromiseState = 'pending'; this.PromiseResult = null; // 这个属性用来保存回调 this.callbacks = []; let resolve = (data) => { // 改变状态 if (this.PromiseState !== 'pending') return; this.PromiseState = 'fulfilled'; this.PromiseResult = data; // 如果异步任务执行时 setTimeout(() => { this.callbacks.forEach(callback => { if (callback.onResolved) { callback.onResolved(data); } }) }); } let reject = (data) => { if (this.PromiseState !== 'pending') return; this.PromiseState = 'rejected'; this.PromiseResult = data; setTimeout(() => { this.callbacks.forEach(callback => { if (callback.onRejected) { callback.onRejected(data); } }) }); } try { // 立即调用执行器函数' executor(resolve, reject); } catch (e) { reject(e); } } } ``` 2. then 方法实现 ```javascript then(onResolved, onRejected) { if (typeof onResolved !== "function") { onResolved = value => value; } if (typeof onRejected !== "function") { onRejected = reason => { throw reason; } } // 调用回调函数 return new Promise((resolve, reject) => { let callback = (resolved) => { try { let result = resolved(this.PromiseResult); if (result instanceof Promise) { result.then(value => { resolve(value); }, reason => { reject(reason); }) } else { resolve(result); } } catch (e) { reject(e); } } if (this.PromiseState === 'fulfilled') { setTimeout(() => { callback(onResolved) }); } if (this.PromiseState === 'rejected') { setTimeout(() => { callback(onRejected) }); } // 异步任务,需要在此保存回调函数 if (this.PromiseState === 'pending') { this.callbacks.push({ onResolved: () => { callback(onResolved); }, onRejected: () => { callback(onRejected); } }) } }) } ``` 3. catch方法 ```javascript catch(onRejected) { return this.then(undefined, onRejected); } ``` 4. 静态方法 resolve ```javascript static resolve(value) { return new Promise((resolve, reject) => { if (value instanceof Promise) { value.then(v => { resolve(v); }, r => { reject(r); }) } else { resolve(value); } }); } ``` 5. 静态方法 reject ```javascript static reject(value) { return new Promise((resolve, reject) => { reject(value); }); } } ``` 6. 静态方法 all ```javascript static all(promises) { return new Promise((resolve, reject) => { let count = 0; let arr = []; for (let i = 0; i < promises.length; i++) { promises[i].then(v => { count++; arr[i] = v; if (count === promises.length) { resolve(arr); } }, r => { reject(r); }) } }) } ``` 7. 静态方法 race ```javascript static race(promises) { return new Promise((resolve, reject) => { for (let i = 0; i < promises.length; i++) { promises[i].then(v => { resolve(v); }, r => { reject(r); }) } }) } ```