【问题标题】:What is wrong with my Javascript promise implementation?我的 Javascript 承诺实现有什么问题?
【发布时间】:2021-05-12 22:42:44
【问题描述】:

我正在尝试构建自己的 Promise,以提高我对 JavaScript 中 Promise 的理解。我目前被困在.then 方法上,我想问一下: 在 .then 这里 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then 的文档中,它说 then 方法返回一个 Promise。我在写这篇文章时遇到了困难,因为this.result 似乎是undefined。为什么会这样,我该如何解决?

这是我的代码:

class LitePromise {
  constructor(fn) {
    if (typeof fn !== "function") {
      throw new TypeError("Promises have to be functions");
    }
    this.fn = fn;
    this.state = PENDING;
    this.result = null;
    const resolveCallback = this.resolve.bind(this);
    const rejectCallback = this.reject.bind(this);
    try {
      fn(resolveCallback, rejectCallback);
    } catch (err) {
      this.reject(err);
    }
  }

  resolve(arg) {
    console.log(arg, "arg");
    this.result = arg;
    this.state = RESOLVED;
  }

  reject() {
    this.state = REJECTED;
  }

  // make an instance of this promise
  then(callback) {
    const tinyPromise = new LitePromise(this.fn);
    console.log(callback, "callback");
    try {
      return tinyPromise.resolve(callback(this.result));
    } catch {
      return tinyPromise.reject(callback(this.result));
    }
  }
}

console.log("------------------");
const yaypromise = new LitePromise((resolve, reject) => {
  console.log("1. running");
  setTimeout(() => {
    console.log("2. resolving");
    resolve("yay");
  }, 100);
}).then((result) => {
  console.log("3. evaluating");
  if (result !== "yay") {
    console.log("Is not working yet");
    return;
  }
  console.log("SUCCESS!", result);
});

【问题讨论】:

  • 这里有各种各样的错误,.then() 可以传递两个回调。您没有.catch() 方法。在 .then() 内部,当你构造一个新的 Promise 时,你不会再次使用 executor 回调函数。在创建原始 Promise 时调用一次且仅一次。 reject() 需要一个理由。
  • 当您调用执行程序时也不要捕获错误(在您的情况下称为fn

标签: javascript asynchronous async-await promise es6-promise


【解决方案1】:

我认为这里的核心问题如下。 then() 通常以两种不同的方式处理:

  1. 承诺待定。存储传递给then() 的回调,并在承诺得到解决时调用这些回调稍后
  2. promise 有结果(解决或拒绝),在这种情况下,我们会尽快调用传递给 then 的回调。

您永远不会处理案例 1,因此如果承诺在 then() 被调用后解决,它将不起作用。

此外,您从then()返回的子承诺应该自己解决传递给then()的回调的结果完成。

如果这听起来非常令人困惑,那是因为它很难 =) 我建议先尝试正确处理您的逻辑,以便仅处理 .then() 中的回调,并且不要从 .then() 返回任何内容

出于同样的原因,我也做出了自己的承诺。它非常小,也许有帮助:

https://github.com/evert/promise-demo/blob/master/src/my-promise.js

【讨论】:

    【解决方案2】:

    这是我们希望与promise 一起使用的示例程序;注意小写p -

    const delay = ms =>
      new promise(r => setTimeout(r, ms))
      
    const roll = n =>
    { console.log("rolling...")
      return delay(1000)
        .then(_ => Math.ceil(Math.random() * n))
        .then(x => { console.log(x); return x })
    }
    
    const main = _ =>
      roll(20).then(x =>
        roll(20).then(y =>
          roll(20).then(z =>
            { console.log("three rolls:", x, y, z)
              return [x,y,z]
            }
          )
        )
      )
    
    main()
      .then(([x,y,z]) => x + y + z)
      .then(sum => console.log("sum:", sum))
      .catch(console.error)
    
    rolling...
    12
    rolling...
    18
    rolling...
    15
    three rolls: 12 18 15
    sum: 45
    

    正如其他人评论的那样,您的代码中有很多需要修复的地方。但是不要难过,因为 Promise 并不是特别容易实现。这是我对promise 的第一张草图。注意valueresolvedrejected 是构造函数的参数,但它们应该是私有的。这可以使用多种技术来完成,但为了简单起见,我暂时保持这种方式。调用者只打算传递第一个参数,exec -

    class promise
    { constructor(exec, value, resolved = false, rejected = false)
      { this.value = value
        this.resolved = resolved
        this.rejected = rejected
        this.callback = []
        if (this.resolved || this.rejected) return
        exec(x => this.resolve(x), e => this.reject(e))
      }
      
      resolve(value)
      { if (this.resolved || this.rejected) return
        let p = promise.resolve(value)
        for (const [ifResolved, ifRejected] of this.callback)
          p = p.then(ifResolved, ifRejected)
        Object.assign(this, p)
      }
      
      reject(value)
      { if (this.resolved || this.rejected) return
        let p = promise.reject(value)
        for (const [ifResolved, ifRejected] of this.callback)
          p = p.then(ifResolved, ifRejected)
        Object.assign(this, p)
      }
      
      then(ifResolved, ifRejected = promise.reject)
      { if (this.resolved)
        { try
          { return promise.resolve(ifResolved(this.value)) }
          catch (err)
          { return promise.reject(err) }
        }
        else if (this.rejected)
        { try
          { return promise.resolve(ifRejected(this.value)) }
          catch (err)
          { return promise.reject(err) }
        }
        else
        { this.callback.push([ifResolved, ifRejected])
          return this
        }
      }
      
      catch(ifRejected)
      { return this.then(value => value, ifRejected) }
      
      static resolve(value)
      { return (value instanceof promise)
          ? value
          : new promise(_ => {}, value, true, false)
      }
      
      static reject(value)
      { return (value instanceof promise)
          ? value
          : new promise(_ => {}, value, false, true)
      }
    }
    

    与 Promise 一样,只有 p.thenp.catch 应该可用于 promise 对象。我们应该阻止用户直接调用p.resolvep.reject,但是现在它可以很容易地看到事情是如何工作的。类函数promise.resolvepromise.reject 类似于Promise.resolvePromise.reject

    展开下面的sn-p,在自己的浏览器中验证结果-

    class promise
    { constructor(exec, value, resolved = false, rejected = false)
      { this.value = value
        this.resolved = resolved
        this.rejected = rejected
        this.callback = []
        if (this.resolved || this.rejected) return
        exec(x => this.resolve(x), e => this.reject(e))
      }
      
      resolve(value)
      { if (this.resolved || this.rejected) return
        let p = promise.resolve(value)
        for (const [ifResolved, ifRejected] of this.callback)
          p = p.then(ifResolved, ifRejected)
        Object.assign(this, p)
      }
      
      reject(value)
      { if (this.resolved || this.rejected) return
        let p = promise.reject(value)
        for (const [ifResolved, ifRejected] of this.callback)
          p = p.then(ifResolved, ifRejected)
        Object.assign(this, p)
      }
      
      then(ifResolved, ifRejected = promise.reject)
      { if (this.resolved)
        { try
          { return promise.resolve(ifResolved(this.value)) }
          catch (err)
          { return promise.reject(err) }
        }
        else if (this.rejected)
        { try
          { return promise.resolve(ifRejected(this.value)) }
          catch (err)
          { return promise.reject(err) }
        }
        else
        { this.callback.push([ifResolved, ifRejected])
          return this
        }
      }
      
      catch(ifRejected)
      { return this.then(value => value, ifRejected) }
      
      static resolve(value)
      { return (value instanceof promise)
          ? value
          : new promise(_ => {}, value, true, false)
      }
      
      static reject(value)
      { return (value instanceof promise)
          ? value
          : new promise(_ => {}, value, false, true)
      }
    }
    
    const delay = ms =>
      new promise(r => setTimeout(r, ms))
      
    const roll = n =>
    { console.log("rolling...")
      return delay(1000)
        .then(_ => Math.ceil(Math.random() * n))
        .then(x => { console.log(x); return x })
    }
    
    const main = _ =>
      roll(20).then(x =>
        roll(20).then(y =>
          roll(20).then(z =>
            { console.log("three rolls:", x, y, z)
              return [x,y,z]
            }
          )
        )
      )
    
    main()
      .then(([x,y,z]) => x + y + z)
      .then(sum => console.log("sum:", sum))
      .catch(console.error)

    我明天会回来添加一个示例来演示错误并回答任何问题(如果有的话)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-08
      • 1970-01-01
      • 2020-09-20
      • 2019-06-20
      • 1970-01-01
      • 2019-06-07
      • 2021-07-25
      • 2011-09-08
      相关资源
      最近更新 更多