Promise icon indicating copy to clipboard operation
Promise copied to clipboard

关于 myPromiseFully.js 中的一些问题

Open 87YLu opened this issue 2 years ago • 1 comments

谢谢你的文章,受益匪浅😁。以下是我发现的一些问题:

[1] Promise.all

根据 mdn 文档,Promise.all() 方法接收一个 promise 的 iterable 类型。 用 Array.isArray 来判断感觉不是很对,用 iterable?.[Symbol.iterator] == null 或许会更合适一些。

在这个基础上,使用 length 来判断迭代的个数就会出现错误了。Set 跟 Map 是没有 length 属性的。 且也不能用 forEach 来遍历,因为如果传入 string 类型会报错。

这样写的话应该好一些:

Promise.all = function (iterable) {
  if (iterable?.[Symbol.iterator] == null) {
    throw new TypeError(
      `${iterable} is not iterable (cannot read property Symbol(Symbol.iterator))`,
    )
  }

  return new Promise((resolve, reject) => {
    let index = 0
    let count = 0
    const result = []
    const length =
      (iterable instanceof Set || iterable instanceof Map) ? iterable.size : iterable.length

    if (length === 0) {
      resolve([])
    }

    for (const item of iterable) {
      if (item instanceof Promise) {
        ;(index => {
          Promise.resolve(item).then(
            value => {
              result[index] = value
              count += 1
              count === length && resolve(result)
            },
            reason => {
              reject(reason)
            },
          )
        })(index)
      } else {
        result[index] = item
        count += 1
        count === length && resolve(result)
      }

      index += 1
    }
  })
}

同理,接收可迭代对象的 promise 方法都应该改一下参数校验的方式。


[2] Promise.resolve

当传入包含 then 方法的对象时,执行的顺序可能会与原生的 promise 有区别。比如

console.log(
  Promise.resolve({
    then() {
      console.log(1)
    },
  }),
)

以上代码,原生 promise 会先打印 promise,再打印 1,而手写的会先打印 1,再打印 promise。

且应该先判断 then 方法是否为一个函数。如果不是的话,会返回整个对象。


[3] Promise.any

errors.push(reason); 会导致 errors 数组的顺序不可控,与原生的 Promise.any 方法有出入。

87YLu avatar Feb 27 '22 14:02 87YLu

能解答下为何手写的符合规范的为何会和原生的不同么 image

new Promise((r)=> { console.log(0) r(); }).then(r=> { console.log(1) return new Promise((r)=> { r(); }) }).then(r=> { console.log(2) }).then(r=> { console.log(3) })

new Promise((r)=> { console.log("zero") r() }).then(r=> { console.log('one'); }).then(r=> { console.log('two'); }).then(r=> { console.log('three'); })

// 原生的promise输出如下 0 zero 1 one two three 2 3

// 您写的输出如下 0 zero 1 one two 2 three 3

tywd avatar Apr 02 '22 07:04 tywd