手写 promise ( 三 ) Promise API 实现

196 阅读4分钟

手写 promise ( 三 ) Promise API 实现

Promise.resolve

Promise.resolve(value) 方法会返回一个新的 Promise 实例,该实例的状态为 fulfilled 。 值有三种情况

  • 普通值
  • thable 对象,含有 then 方法的对象
  • promise 如果值是 promise 将对象返回,如果是普通值将值转化为 Promise 对象执行 resolve 方法,如果是 thenable 对象,将该对象转化为 Promise 对象,执行 then 方法。

案例

let p = Promise.resolve(1)
// 等价于 let p = new Promise(res=>{res(1)})
p.then(res=>{
    console.log('res',res)
})
// res 1

实现

...

const isPromise = (val) => {
  if ((typeof val === "object" && val != null) || typeof val == "function") {
    if (typeof val.then == "function") {
      return true;
    } else {
      return false;
    }
  } else {
    return false;
  }
};

MyPromise.resolve = (val) => {
  if (isPromise(val)) {
    return val;
  }
  return new MyPromise((res, rej) => {
    res(val);
  });
};
...

Promise.reject

Promise.reject(reason) 方法也会返回一个新的 Promise 实例,该实例的状态为 rejected

案例

let p = Promise.reject(1)
// 等价于 let p = new Promise(res=>{res(1)})
p.then(null,err=>{
    console.log('err',err)
})
// err 1

实现

...
MyPromise.reject = (reason) => {
  return new MyPromise((res, rej) => {
    rej(reason);
  });
};
...

Promise.all

Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.all([p1, p2, p3]);

p 的状态由 p1、p2、p3 决定,分成两种情况。

  • 只有 p1、p2、p3 的状态都变成 fulfilledp 的状态才会变成 fulfilled ,此时 p1、p2、p3 的返回值组成一个数组,传递给p的回调函数。
  • 只要 p1、p2、p3 之中有一个被 rejectedp 的状态就变成 rejected ,此时第一个被 reject 的实例的返回值,会传递给 p 的回调函数。

案例

let promise1 = Promise.resolve(1);
let promise2 = Promise.resolve(2);
let promise3 = Promise.reject(3);
let promises = [1, promise2, 3];

Promise.all(promises).then(
  (array) => {
    console.log("array", array);
  },
  (err) => {
      console.log("err", err);
  }
);
// array [ 1, 2, 3 ];

let promises2 = [1, promise2, promise3];

Promise.all(promises2).then(
  (array) => {
    console.log("array", array);
  },
  (err) => {
      console.log("err", err);
  }
);
// err 3

let promises2 = [promise3, promise2, 4];

Promise.all(promises2).then(
  (array) => {
    console.log("array", array);
  },
  (err) => {
      console.log("err", err);
  }
);
// err 3

实现

MyPromise.all = (values) => {
  return new MyPromise((resolve, reject) => {
    if (Array.isArray(values)) {
      let resultArr = [];
      let count = 0;
      values.forEach((val, idx) => {
        Promise.resolve(val)
          .then((res) => {
            resultArr[idx] = res;
            count++;

            if (count === values.length) {
              resolve(resultArr);
            }
          })
          .catch((err) => {
            reject(err);
          });
      });
    } else {
      reject(new Error("Array Methods must be provided an Array"));
    }
  });
};

Promise.catch

cath 方法其实就是 then 方法的语法糖

案例

let p = new Promise((resolve, reject) => {
  reject(new Error("错喽 错喽"));
});

p.then((res) => {
  console.log("res", res);
}).catch((err) => {
  console.log("err", err);
});
// err Error: 错喽 错喽

实现

class MyPromise{
    ...
    // mark then 方法的语法糖
    catch(errCallback) {
        return this.then(null, errCallback);
    }
}
...

Promise.finall

finally 方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。 finally 后可以链式调用 then 方法,所以返回值是 Promisefinally 的回调可能是一个异步函数,如果直接调用回调,这里其实异步代码没走完,就拿到上个 Promise 的值,这里用 Promise.resolve 处理。在 Promise 里我们已经写了对于异步函数的处理。

案例

function p1 () {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      resolve("p1")
    }, 2000);
  })
}
function p2 () {
  return new Promise(function (resolve, reject) {
    reject("失败")
    // resolve("p2 成功")
  })
}

p2().finally(() => {
  console.log("finally");
  return p1();
}).then(value => {
  console.log(value);
}, reason => {
  console.log(reason);
})

实现

class MyPromise{
    ...
    /**
     * 无论 Promise 的状态如何都会执行
     * @param {Function} callback 回调函数
     * @returns {MyPromise}
     */
  finally(callback) {
    return this.then(
      (resolve) => {
        // mark 利用 MyPromise 对异步函数的处理机制,处理回调是异步函数的情况
        return MyPromise.resolve(callback()).then(() => resolve);
      },
      (reject) => {
        return MyPromise.resolve(callback()).then(() => {
          throw reject;
        });
      }
    );
  }
}
...

Promise.race

Promise.race 方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.race([p1, p2, p3]);

上面代码中,只要 p1、p2、p3 之中有一个实例率先改变状态,p 的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

Promise.race方法的参数与Promise.all方法一样,如果不是 Promise 实例,就会先调用 Promise.resolve 方法,将参数转为 Promise 实例,再进一步处理。

案例

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("p1");
  }, 100);
});

const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("p2");
  }, 200);
});

const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("p3");
  }, 300);
  // }, 30);
});

Promise.race([p1,p2,p3]).then(
  (res) => {
    console.log("res", res);
  },
  (err) => {
    console.log("err", err);
  }
);

实现

...
MyPromise.race = (values) => {
  return new MyPromise((resolve, reject) => {
    if (Array.isArray(values)) {
      values.forEach((val) => {
        MyPromise.resolve(val)
          .then((res) => {
            resolve(res);
          })
          .catch((err) => {
            reject(err);
          });
      });
    } else {
      reject(new Error("Array Methods must be provided an Array"));
    }
  });
};
...

Promise.allSettled

有时候,我们希望等到一组异步操作都结束了,不管每一个操作是成功还是失败,再进行下一步操作。但是,现有的 Promise 方法很难实现这个要求。 Promise.all 方法只适合所有异步操作都成功的情况,如果有一个操作失败,就无法满足要求。所以又了 Promise.allSettled

Promise.allSettled 方法接受一个数组作为参数,数组的每个成员都是一个 Promise 对象,并返回一个新的 Promise 对象。等到数组所有 Promise 对象都发生状态变更(不管是 fulfilled 还是 rejected ),返回的 Promise 对象才会发生状态变更且状态总是 fulfilled ,不会变成 rejected

案例

const p1 = Promise.resolve('p1');
const p2 = new Promise((resolve) => {
  setTimeout(() => resolve("p2"), 1000);
});
const p3 = new Promise((resolve) => {
  setTimeout(() => resolve("p3"), 3000);
});

const p4 = Promise.reject("err p4");
const p5 = Promise.reject("err p5");
// 1. 所有的Promise都成功了
Promise.allSettled([p1, p2, p3]).then((res) => console.log("res", res));
/**
 res [
  { status: 'fulfilled', value: 'p1' },
  { status: 'fulfilled', value: 'p2' },
  { status: 'fulfilled', value: 'p3' }
]
 */

// 2. 有一个Promise失败了
Promise.allSettled([p1, p2, p4]).then((res) =>
  console.log(JSON.stringify(res, null, 2))
);
/**
 res [
  { status: 'fulfilled', value: 'p1' },
  { status: 'fulfilled', value: 'p2' },
  { status: 'rejected', reason: 'err p4' }
]
 */

// 3. 有两个Promise失败了
Promise.allSettled([p1, p4, p5]).then((res) =>
  console.log(JSON.stringify(res, null, 2))
);
/**
 res [
  { status: 'fulfilled', value: 'p1' },
  { status: 'rejected', reason: 'err p4' }
  { status: 'rejected', reason: 'err p5' }
]
 */

实现

...
MyPromise.allSettled = (values) => {
  return new MyPromise((resolve, reject) => {
    if (Array.isArray(values)) {
      let resultArr = [];
      let count = 0;

      values.forEach((val, idx) => {
        MyPromise.resolve(val)
          .then((res) => {
            count++;
            resultArr[idx] = {
              status: "fulfilled",
              value: res,
            };
            if (count === values.length) {
              resolve(resultArr);
            }
          })
          .catch((err) => {
            count++;
            resultArr[idx] = {
              status: "rejected",
              reason: err,
            };
            if (count === values.length) {
              resolve(resultArr);
            }
          });
      });
    } else {
      reject(new Error("Array Methods must be provided an Array"));
    }
  });
};
...

PS

  • 代码仓库地址觉得对你有帮助记得 🌟 Star 哦
  • 后续会持续更新相关内容以及其他内容
  • 觉得文章不错的话,记得 👍 🌟 嘻嘻
  • 如有不足欢迎指正