Promise与Promise.all的基本使用,手写Promise

4 阅读1分钟

在现代 JavaScript 编程中,异步操作已经成为开发中不可或缺的一部分,而 Promise 则是处理异步操作的核心工具。随着异步编程需求的增加,JavaScript 提供了多种处理方式,其中 PromisePromise.all 是两个非常重要且常用的异步操作方法。在本文中,我们将深入探讨 Promise 及其进阶用法 Promise.all,并讨论它们的使用场景和最佳实践。

1. Promise 的基本概念

Promise 是一种用于处理异步操作的对象。它代表着一个在未来可能完成或失败的操作,并且能够以一种线性、直观的方式来处理异步逻辑。 Promise 对象有三种状态:

  • Pending(待定):初始状态,操作尚未完成。
  • Fulfilled(已完成):操作成功完成。
  • Rejected(已拒绝):操作失败。

一个 Promise 的典型使用方式如下:

new Promise((resolve, reject) => {
    // 执行一些异步操作
    setTimeout(() => {
        let success = true;
        if (success) {
            resolve("操作成功!");
        } else {
            reject("操作失败!");
        }
    }, 1000);
}).then(result => {
    console.log(result); // "操作成功!"
}).catch(error => {
    console.log(error); // "操作失败!"
});

在这个例子中, Promise 被创建后,它会立即执行传入的函数,并在操作完成时调用 resolvereject,然后通过 then 方法处理成功的结果,通过 catch 方法处理失败的情况。

2. Promise.all 的使用场景

Promise.allPromise 的一个高级用法,适用于当我们有多个异步操作需要并行执行,并且希望在所有操作都成功后继续执行后续逻辑时。它接收一个包含多个 Promise 对象的数组,并返回一个新的 Promise 对象。

Promise.all 的工作机制如下:

  • 当数组中的所有 Promise 对象都 Fulfilled 时, Promise.all 返回的 Promise 状态变为 Fulfilled,并返回一个包含所有 Promise 返回值的数组。
  • 如果数组中的任意一个 Promise 进入 Rejected 状态, Promise.all 返回的 Promise 状态立即变为 Rejected,并返回第一个 Rejected 的错误。

下面是一个 Promise.all 的简单示例:

let promise1 = Promise.resolve(3);
let promise2 = 42;
let promise3 = new Promise((resolve, reject) => {
    setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3])
    .then(values => {
        console.log(values); // [3, 42, "foo"]
    })
    .catch(error => {
        console.log(error);
    });

在这个例子中, Promise.all 接收了三个 Promise,它们都成功了,因此 then 回调函数会接收到一个数组,包含三个 Promise 返回的值。

3. 使用 Promise.all 处理并行异步操作

在实际开发中,我们常常需要同时处理多个异步操作,例如从多个 API 获取数据、并行处理多个文件或数据库查询等。这种情况下, Promise.all 可以有效地提高代码的执行效率,因为它可以同时发起所有请求,而不是一个接一个地等待前一个请求完成。

举个例子,假设我们需要从三个不同的 API 获取数据,然后将这些数据进行处理:

function fetchData(url) {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(`Data from ${url}`);
        }, Math.random() * 1000);
    });
}

Promise.all([
    fetchData('https://api1.com'),
    fetchData('https://api2.com'),
    fetchData('https://api3.com')
]).then(results => {
    console.log(results);
}).catch(error => {
    console.log(error);
});

在这个例子中,三个 fetchData 请求会同时开始,并且 Promise.all 会等待所有请求都完成后再继续处理结果。

4. Promise.all 的注意事项

虽然 Promise.all 提供了一种强大的并行处理方式,但也有一些需要注意的地方:

5. 手写Promise

class NewPromise {
  constructor(func) {
    //判断当前执行到第几个then和catch的回调函数
    this.currentIndex = 0;
    //resolve函数,执行当前索引后面最近的then的回调函数
    this.res = (arg) => {
      //找到最近的一个then的回调函数
      for (let i = this.currentIndex; i < this.funcArr.length; i++) {
        if (this.funcArr[i].type === "then") {
          this.currentIndex++;
          break;
        }
      }
      //记录返回值
      const resReturn = this.funcArr[this.currentIndex - 1].func(arg);
      //判断返回值是否存在,如不存在则执行finally,如存在则判断类型是否为NewPromise也就是此类
      if (resReturn) {
        if (resReturn instanceof NewPromise) {
          resReturn.currentIndex = this.currentIndex;
          resReturn.funcArr = this.funcArr;
          resReturn.finallyFunc = this.finallyFunc;
        } else {
          this.res(resReturn);
        }
      } else {
        if (this.finallyFunc) {
          this.finallyFunc();
        }
      }
    };
    //reject函数,执行当前索引后面最近的catch的回调函数
    this.rej = (arg) => {
      //找到最近的一个catch的回调函数
      for (let i = this.currentIndex; i < this.funcArr.length; i++) {
        if (this.funcArr[i].type === "catch") {
          this.currentIndex++;
          break;
        }
      }
      const rejReturn = this.funcArr[this.currentIndex - 1].func(arg);
      //判断返回值是否存在,如不存在则执行finally,如存在则判断类型是否为NewPromise也就是此类
      if (rejReturn) {
        if (resReturn instanceof NewPromise) {
          resReturn.currentIndex = this.currentIndex;
          resReturn.funcArr = this.funcArr;
          resReturn.finallyFunc = this.finallyFunc;
        } else {
          this.rej(resReturn);
        }
      } else {
        if (this.finallyFunc) {
          this.finallyFunc();
        }
      }
    };
    //预备数组,记录全部回调函数,并以对象形式储存,其中包括type判断是then还是catch,以及对应的函数指针
    this.funcArr = [];
    //保存finally回调函数
    this.finallyFunc;
    //执行newpromise的参数函数,并将写好的reslove和reject函数传入
    func(this.res, this.rej);
  }
  //then,将传入的函数放入预备数组
  then(func) {
    this.funcArr.push({
      type: "then",
      func,
    });
    return this;
  }
  //catch,将传入的函数防御预备数组
  catch(func) {
    this.funcArr.push({
      type: "catch",
      func,
    });
    return this;
  }
  //finally,最终必须执行的函数
  finally(func) {
    this.finallyFunc = func;
  }
}
new NewPromise((res, rej) => {
  setTimeout(() => {
    res(6);
  }, 1000);
})
  .then((res) => {
    console.log(res);
  })
  .catch((rej) => {
    console.log(rej);
  });