Appearance
js手写 Promise
本节目标:理解“js手写 Promise”的核心思路,并能把它用于实际开发或面试表达。
==const PENDING = "pending";========const RESOLVED = "resolved";========const REJECTED = "rejected";======
==function MyPromise(fn) {====== ==//== ==保存初始化状态====== ==var self = this;======
==//== ==初始化状态====== ==this.state = PENDING;======
==//== ==用于保存== ==resolve== ==或者== ==rejected== ==传入的值====== ==this.value = null;======
==//== ==用于保存== ==resolve== ==的回调函数====== ==this.resolvedCallbacks = [];======
==//== ==用于保存== ==reject== ==的回调函数====== ==this.rejectedCallbacks = [];======
==//== ==状态转变为== ==resolved== ==方法====== ==function resolve(value) {====== ==//== ==判断传入元素是否为== ==Promise== ==值,如果是,则状态改变必须等待前一个状态改变后再进行改变====== ==if (value instanceof MyPromise) {====== ==return value.then(resolve, reject);====== ==}======
==//== ==保证代码的执行顺序为本轮事件循环的末尾====== ==setTimeout(() => {====== ==//== ==只有状态为== ==pending== ==时才能转变,====== ==if (self.state === PENDING) {====== ==//== ==修改状态====== ==self.state = RESOLVED;======
==//== ==设置传入的值====== ==self.value = value;======
==//== ==执行回调函数====== ==self.resolvedCallbacks.forEach(callback => {====== ==callback(value);====== ==});====== ==}====== ==}, 0);====== ==}======
==//== ==状态转变为== ==rejected== ==方法====== ==function reject(value) {====== ==//== ==保证代码的执行顺序为本轮事件循环的末尾====== ==setTimeout(() => {====== ==//== ==只有状态为== ==pending== ==时才能转变====== ==if (self.state === PENDING) {====== ==//== ==修改状态====== ==self.state = REJECTED;======
==//== ==设置传入的值====== ==self.value = value;======
==//== ==执行回调函数====== ==self.rejectedCallbacks.forEach(callback => {====== ==callback(value);====== ==});====== ==}====== ==}, 0);====== ==}======
==//== ==将两个方法传入函数执行====== ==try {====== ==fn(resolve, reject);====== ==} catch (e) {====== ==//== ==遇到错误时,捕获错误,执行== ==reject== ==函数====== ==reject(e);====== ==}========}======
==MyPromise.prototype.then = function(onResolved, onRejected) {====== ==//== ==首先判断两个参数是否为函数类型,因为这两个参数是可选参数====== ==onResolved ======= ==typeof onResolved === "function"====== ==? onResolved====== ==: function(value) {====== ==return value;====== ==};======
==onRejected ======= ==typeof onRejected === "function"====== ==? onRejected====== ==: function(error) {====== ==throw error;====== ==};======
==//== ==如果是等待状态,则将函数加入对应列表中====== ==if (this.state === PENDING) {====== ==this.resolvedCallbacks.push(onResolved);====== ==this.rejectedCallbacks.push(onRejected);====== ==}======
==//== ==如果状态已经凝固,则直接执行对应状态的函数======
==if (this.state === RESOLVED) {====== ==onResolved(this.value);====== ==}======
==if (this.state === REJECTED) {====== ==onRejected(this.value);====== ==}========};======
==折叠==
**5. 手写 Promise.then**
==then== 方法返回一个新的 ==promise== 实例,为了在 ==promise== 状态发生变化时(==resolve== / ==reject== 被调用时)再执行 ==then== 里的函数,我们使用一个 ==callbacks== 数组先把传给then的函数暂存起来,等状态改变时再调用。承前:当前一个 ==promise== 完成后,调用其 ==resolve== 变更状态,在这个 ==resolve== 里会依次调用 ==callbacks== 里的回调,这样就执行了 ==then== 里的方法了
启后:上一步中,当 ==then== 里的方法执行完成后,返回一个结果,如果这个结果是个简单的值,就直接调用新 ==promise== 的 ==resolve==,让其状态变更,这又会依次调用新 ==promise== 的 ==callbacks== 数组里的方法,循环往复。。如果返回的结果是个 ==promise==,则需要等它完成之后再触发新 ==promise== 的 ==resolve==,所以可以在其结果的 ==then== 里调用新 ==promise== 的 ==resolve==
==then(onFulfilled, onReject){====== ==//== ==保存前一个====promise====的====this====== ==const self = this;== ==== ==return new MyPromise((resolve, reject) => {====== ==//== ==封装前一个====promise====成功时执行的函数====== ==let fulfilled = () => {====== ==try{====== ==const result = onFulfilled(self.value); //== ==承前====== ==return result instanceof MyPromise? result.then(resolve, reject) : resolve(result); //====启后====== ==}catch(err){====== ==reject(err)====== ==}====== ==}====== ==//== ==封装前一个====promise====失败时执行的函数====== ==let rejected = () => {====== ==try{====== ==const result = onReject(self.reason);====== ==return result instanceof MyPromise? result.then(resolve, reject) : reject(result);====== ==}catch(err){====== ==reject(err)====== ==}====== ==}====== ==switch(self.status){====== ==case PENDING:== ==== ==self.onFulfilledCallbacks.push(fulfilled);====== ==self.onRejectedCallbacks.push(rejected);====== ==break;====== ==case FULFILLED:====== ==fulfilled();====== ==break;====== ==case REJECT:====== ==rejected();====== ==break;====== ==}====== ==})====== ==}======连续多个 ==then== 里的回调方法是同步注册的,但注册到了不同的 ==callbacks== 数组中,因为每次 ==then== 都返回新的 ==promise== 实例(参考上面的例子和图)
注册完成后开始执行构造函数中的异步事件,异步完成之后依次调用 ==callbacks== 数组中提前注册的回调**6. 手写 Promise.all**
**1) 核心思路**接收一个 Promise 实例的数组或具有 Iterator 接口的对象作为参数这个方法返回一个新的 promise 对象,遍历传入的参数,用Promise.resolve()将参数"包一层",使其变成一个promise对象参数所有回调成功才是成功,返回值数组与参数顺序一致参数数组其中一个失败,则触发失败状态,第一个触发失败的 Promise 错误信息作为 Promise.all 的错误信息。
**2)实现代码**
一般来说,Promise.all 用来处理多个并发请求,也是为了页面数据构造的方便,将一个页面所用到的在不同接口的数据一起请求过来,不过,如果其中一个接口失败了,多个请求也就失败了,页面可能啥也出不来,这就看当前页面的耦合程度了
==function promiseAll(promises) {====== ==return new Promise(function(resolve, reject) {====== ==if(!Array.isArray(promises)){====== ==throw new TypeError(`argument must be a array`)====== ==}====== ==var resolvedCounter = 0;====== ==var promiseNum = promises.length;====== ==var resolvedResult = [];====== ==for (let i = 0; i < promiseNum; i++) {====== ==Promise.resolve(promises[i]).then(value=>{====== ==resolvedCounter++;====== ==resolvedResult[i] = value;====== ==if (resolvedCounter == promiseNum) {====== ==return resolve(resolvedResult)====== ==}====== ==},error=>{====== ==return reject(error)====== ==})====== ==}====== ==})========}========// test========let p1 = new Promise(function (resolve, reject) {====== ==setTimeout(function () {====== ==resolve(1)====== ==}, 1000)========})========let p2 = new Promise(function (resolve, reject) {====== ==setTimeout(function () {====== ==resolve(2)====== ==}, 2000)========})========let p3 = new Promise(function (resolve, reject) {====== ==setTimeout(function () {====== ==resolve(3)====== ==}, 3000)========})========promiseAll([p3, p1, p2]).then(res => {====== ==console.log(res) // [3, 1, 2]========})======
**7. 手写 Promise.race**
该方法的参数是 Promise 实例数组, 然后其 then 注册的回调方法是数组中的某一个 Promise 的状态变为 fulfilled 的时候就执行. 因为 Promise 的状态**只能改变一次**, 那么我们只需要把 Promise.race 中产生的 Promise 对象的 resolve 方法, 注入到数组中的每一个 Promise 实例中的回调函数中即可.
==Promise.race = function (args) {====== ==return new Promise((resolve, reject) => {====== ==for (let i = 0, len = args.length; i < len; i++) {====== ==args[i].then(resolve, reject)====== ==}====== ==})========}======那么,怎么保证后一个 then 里的方法在前一个 then**(可能是异步)结束之后再执行呢?** 我们可以将传给 ==then== 的函数和新 ==promise== 的 ==resolve== 一起 ==push== 到前一个 ==promise== 的 ==callbacks== 数组中,达到承前启后的效果: 注意:
