介绍下 promise 的特性、优缺点,内部是如何实现的并动手实现 Promise、Promise.all

本文深入探讨了Promise的基本概念、特性、优缺点,并提供了Promise及Promise.all的实现代码。通过具体示例展示了如何使用自定义Promise处理异步操作。

1)Promise基本特性

  • 1、Promise有三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)
  • 2、Promise对象接受一个回调函数作为参数, 该回调函数接受两个参数,分别是成功时的回调resolve和失败时的回调reject;另外resolve的参数除了正常值以外, 还可能是一个Promise对象的实例;reject的参数通常是一个Error对象的实例。
  • 3、then方法返回一个新的Promise实例,并接收两个参数onResolved(fulfilled状态的回调);onRejected(rejected状态的回调,该参数可选)
  • 4、catch方法返回一个新的Promise实例
  • 5、finally方法不管Promise状态如何都会执行,该方法的回调函数不接受任何参数
  • 6、Promise.all()方法将多个多个Promise实例,包装成一个新的Promise实例,该方法接受一个由Promise对象组成的数组作为参数(Promise.all()方法的参数可以不是数组,但必须具有Iterator接口,且返回的每个成员都是Promise实例),注意参数中只要有一个实例触发catch方法,都会触发Promise.all()方法返回的新的实例的catch方法,如果参数中的某个实例本身调用了catch方法,将不会触发Promise.all()方法返回的新实例的catch方法
  • 7、Promise.race()方法的参数与Promise.all方法一样,参数中的实例只要有一个率先改变状态就会将该实例的状态传给Promise.race()方法,并将返回值作为Promise.race()方法产生的Promise实例的返回值
  • 8、Promise.resolve()将现有对象转为Promise对象,如果该方法的参数为一个Promise对象,Promise.resolve()将不做任何处理;如果参数thenable对象(即具有then方法),Promise.resolve()将该对象转为Promise对象并立即执行then方法;如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的Promise对象,状态为fulfilled,其参数将会作为then方法中onResolved回调函数的参数,如果Promise.resolve方法不带参数,会直接返回一个fulfilled状态的 Promise 对象。需要注意的是,立即resolve()的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时。
  • 9、Promise.reject()同样返回一个新的Promise对象,状态为rejected,无论传入任何参数都将作为reject()的参数

2)Promise优点

  • ①统一异步 API
    • Promise 的一个重要优点是它将逐渐被用作浏览器的异步 API ,统一现在各种各样的 API ,以及不兼容的模式和手法。
  • ②Promise 与事件对比
    • 和事件相比较, Promise 更适合处理一次性的结果。在结果计算出来之前或之后注册回调函数都是可以的,都可以拿到正确的值。 Promise 的这个优点很自然。但是,不能使用 Promise 处理多次触发的事件。链式处理是 Promise 的又一优点,但是事件却不能这样链式处理。
  • ③Promise 与回调对比
    • 解决了回调地狱的问题,将异步操作以同步操作的流程表达出来。
  • ④Promise 带来的额外好处是包含了更好的错误处理方式(包含了异常处理),并且写起来很轻松(因为可以重用一些同步的工具,比如 Array.prototype.map() )。

3)Promise缺点

  • 1、无法取消Promise,一旦新建它就会立即执行,无法中途取消。
  • 2、如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
  • 3、当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
  • 4、Promise 真正执行回调的时候,定义 Promise 那部分实际上已经走完了,所以 Promise 的报错堆栈上下文不太友好。
  • 5、Promise 只能有一个最终值或一个最终错误,无法同时返回多个值。

实现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]
})

实现 Promise:

下面是一个简单的 Promise 实现,仅包含异步成功和失败的处理:

class MyPromise {
  constructor(executor) {
    this.state = 'pending';
    this.result = undefined;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.result = value;
        this.onFulfilledCallbacks.forEach(callback => callback(value));
      }
    };

    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.result = reason;
        this.onRejectedCallbacks.forEach(callback => callback(reason));
      }
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      const handle = (callback) => {
        try {
          const result = callback(this.result);
          if (result instanceof MyPromise) {
            result.then(resolve, reject);
          } else {
            resolve(result);
          }
        } catch (error) {
          reject(error);
        }
      };

      if (this.state === 'fulfilled') {
        handle(onFulfilled);
      } else if (this.state === 'rejected') {
        handle(onRejected);
      } else {
        this.onFulfilledCallbacks.push(() => handle(onFulfilled));
        this.onRejectedCallbacks.push(() => handle(onRejected));
      }
    });
  }

  catch(onRejected) {
    return this.then(undefined, onRejected);
  }
}

// 示例用法
const promise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('Success!');
    // reject('Error!');
  }, 1000);
});

promise
  .then(result => {
    console.log('Fulfilled:', result);
    return result.toUpperCase();
  })
  .then(result => {
    console.log('Modified result:', result);
  })
  .catch(error => {
    console.error('Rejected:', error);
  });

 大厂面试可用

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

const resolvePromise = (promise, x, resolve, reject) => {
  if (x === promise) {
    // If promise and x refer to the same object, reject promise with a TypeError as the reason.
    reject(new TypeError('循环引用'))
  }
  // if x is an object or function,
  if (x !== null && typeof x === 'object' || typeof x === 'function') {
    // If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored.
    let called
    try { // If retrieving the property x.then results in a thrown exception e, reject promise with e as the reason.
      let then = x.then // Let then be x.then
      // If then is a function, call it with x as this
      if (typeof then === 'function') {
        // If/when resolvePromise is called with a value y, run [[Resolve]](promise, y)
        // If/when rejectPromise is called with a reason r, reject promise with r.
        then.call(x, y => {
          if (called) return
          called = true
          resolvePromise(promise, y, resolve, reject)
        }, r => {
          if (called) return
          called = true
          reject(r)
        })
      } else {
        // If then is not a function, fulfill promise with x.
        resolve(x)
      }
    } catch (e) {
      if (called) return
      called = true
      reject(e)
    }
  } else {
    // If x is not an object or function, fulfill promise with x
    resolve(x)
  }
}

class Promise {
  constructor(executor) {
    this.status = PENDING
    this.value = undefined
    this.reason = undefined
    // 存放成功/失败的队列
    this.onFulfilledCallbacks = []
    this.onRejectedCallbacks = []

    const resolve = (value) => {
      // 如果value是一个Promise 递归解析
      if (value instanceof Promise) {
        return value.then(resolve, reject)
      }
      if (this.status === PENDING) {
        this.status = FULFILLED
        this.value = value
        this.onFulfilledCallbacks.forEach(fn => fn())
      }
    }
    const reject = (reason) => {
      if (this.status === PENDING) {
        this.status = REJECTED
        this.reason = reason
        this.onRejectedCallbacks.forEach(fn => fn())
      }
    }
    try {
      executor(resolve, reject) // 立即执行
    } catch (error) {
      reject(error)
    }
  }
  then(onFulfilled, onRejected) {
    // 判断 onFulfilled, onRejected 是否是函数
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
    let newPromise = new Promise((resolve, reject) => {
      if (this.status === FULFILLED) {
        setTimeout(() => {
          try {
            let x = onFulfilled(this.value)
            resolvePromise(newPromise, x, resolve, reject)
          } catch (error) {
            reject(error)
          }

        })
      }
      if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = onRejected(this.reason)
            resolvePromise(newPromise, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })

      }
      if (this.status === PENDING) {
        this.onFulfilledCallbacks.push((() => {
          setTimeout(() => {
            try {
              let x = onFulfilled(this.value)
              resolvePromise(newPromise, x, resolve, reject)
            } catch (error) {
              reject(error)
            }
          })
        }))
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onRejected(this.reason)
              resolvePromise(newPromise, x, resolve, reject)
            } catch (error) {
              reject(error)
            }
          })
        })
      }
    })
    return newPromise
  }
  /**
   * Promise.catch
   * @description  用于promise方法链示,捕获前面 onFulfilled/onRejected 抛出的异常
   * @param {*} errorCallback 
   */
  catch(errorCallback) {
    return this.then(null, errorCallback)
  }
  /**
   * Promise.finally
   * @description finally 传入的函数 无论成功和失败都执行
   * @param {*} callback 回调函数
   * @returns 返回成功/失败
   */
  finally(callback) {
    return this.then((value) => {
      // 返回上一次的值
      return new Promise(callback()).then(() => value)
    }, error => {
      return new Promise(callback()).then(() => { throw error })
    })
  }
  /**
   * Promise.all
   * @description 当这个数组里的所有promise对象全部变为resolve状态的时候,才会resolve 当有一个promise对象变为reject状态时 直接 reject
   * @param {*} values promise对象组成的数组作为参数
   * @returns 返回一个promise实例
   */
  static all(values) {
    return new Promise((resolve, reject) => {
      let resultArr = []
      let count = 0
      const resultArrByKey = (index, value) => {
        resultArr[index] = value
        if (++count === values.length) {
          resolve(resultArr)
        }
      }
      values.forEach((promise, index) => {
        promise.then((value) => {
          resultArrByKey(index, value)
        }, reject)
      })
    })
  }
  /**
   * Promise.race
   * @description 只要有一个promise对象进入FULFILLED 或者  REJECTED 状态的话,就会继续执行后面的处理
   * @param {*} values  接受promise对象组成的数组作为参数
   * @returns 返回一个Promise实例
   */
  static race(values) {
    return new Promise((resolve, reject) => {
      values.forEach((promise) => {
        promise.then(resolve, reject)
      })
    })
  }
  // 默认产生一个成功的promise
  static resolve(value) {
    return new Promise((resolve, reject) => {
      resolve(value)
    })
  }
  // 默认产生一个失败的promise
  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }
}

Promise.deferred = () => {
  let defer = {}
  defer.promise = new Promise((resolve, reject) => {
    defer.resolve = resolve
    defer.reject = reject
  })
  return defer
}

module.exports = Promise

实现promise和then

要实现一个简单的 Promise,首先需要了解 Promise 的核心概念和功能:

  1. Promise 状态:一个 Promise 有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。一旦状态改变,就不可再改变。

  2. then 方法Promise 实例可以通过 then 方法注册回调函数,用于在 Promise 成功或失败后执行相应的操作。

  3. resolve 和 rejectPromise 的状态可以通过 resolve 方法(将状态变为 fulfilled)或 reject 方法(将状态变为 rejected)来改变。

  4. 链式调用then 方法返回一个新的 Promise,因此可以链式调用。

一、基本实现

我们可以从实现一个基础的 Promise 开始,包括状态管理和 then 方法。

1. 构造函数和状态管理

首先,我们需要构造一个 Promise 类,并在其中初始化状态、值和回调函数。

class MyPromise {
    constructor(executor) {
        this.state = 'pending'; // 初始状态为 pending
        this.value = undefined; // 成功的值
        this.reason = undefined; // 失败的原因

        this.onFulfilledCallbacks = []; // 成功的回调
        this.onRejectedCallbacks = [];  // 失败的回调

        // resolve 函数,用于将状态变为 fulfilled
        const resolve = (value) => {
            if (this.state === 'pending') {
                this.state = 'fulfilled';
                this.value = value;
                this.onFulfilledCallbacks.forEach(fn => fn());
            }
        };

        // reject 函数,用于将状态变为 rejected
        const reject = (reason) => {
            if (this.state === 'pending') {
                this.state = 'rejected';
                this.reason = reason;
                this.onRejectedCallbacks.forEach(fn => fn());
            }
        };

        try {
            executor(resolve, reject); // 执行传入的函数,并将 resolve 和 reject 作为参数
        } catch (error) {
            reject(error); // 如果执行时出错,直接 reject
        }
    }
}
2. 实现 then 方法

接下来,我们需要实现 then 方法,该方法用于注册成功和失败的回调。

MyPromise.prototype.then = function(onFulfilled, onRejected) {
    // 如果 onFulfilled 不是函数,给它一个默认值
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    // 如果 onRejected 不是函数,给它一个默认值
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

    // 返回一个新的 Promise,支持链式调用
    return new MyPromise((resolve, reject) => {
        if (this.state === 'fulfilled') {
            // 异步执行 onFulfilled 回调
            setTimeout(() => {
                try {
                    const x = onFulfilled(this.value);
                    resolve(x); // 将 onFulfilled 的返回值传递给下一个 promise
                } catch (error) {
                    reject(error); // 捕获错误并传递给下一个 promise
                }
            });
        } else if (this.state === 'rejected') {
            // 异步执行 onRejected 回调
            setTimeout(() => {
                try {
                    const x = onRejected(this.reason);
                    resolve(x); // 将 onRejected 的返回值传递给下一个 promise
                } catch (error) {
                    reject(error); // 捕获错误并传递给下一个 promise
                }
            });
        } else if (this.state === 'pending') {
            // 将回调存储起来,等到 promise 状态改变时再执行
            this.onFulfilledCallbacks.push(() => {
                setTimeout(() => {
                    try {
                        const x = onFulfilled(this.value);
                        resolve(x);
                    } catch (error) {
                        reject(error);
                    }
                });
            });

            this.onRejectedCallbacks.push(() => {
                setTimeout(() => {
                    try {
                        const x = onRejected(this.reason);
                        resolve(x);
                    } catch (error) {
                        reject(error);
                    }
                });
            });
        }
    });
};

二、测试自定义的 Promise

让我们测试一下这个简单的 Promise 实现。

1. 基本用法
const promise = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('Success!');
    }, 1000);
});

promise.then(value => {
    console.log(value); // 输出: 'Success!'
}).catch(reason => {
    console.error(reason);
});
2. 链式调用
const promise = new MyPromise((resolve, reject) => {
    resolve(42);
});

promise
    .then(value => {
        console.log(value); // 输出: 42
        return value + 1;
    })
    .then(value => {
        console.log(value); // 输出: 43
        throw new Error('Something went wrong');
    })
    .catch(error => {
        console.error(error); // 输出: 'Error: Something went wrong'
    });

三、总结

这个简单的 Promise 实现涵盖了 Promise 的基本概念,包括状态管理、回调处理、链式调用和错误处理。这个实现是简化版的,原生 Promise 的一些高级特性如 Promise.allPromise.racefinally 方法和微任务队列等未包括在内。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值