简体   繁体   English

我的 Javascript promise 实现有什么问题?

[英]What is wrong with my Javascript promise implementation?

I'm trying to build my own Promise to improve my understanding of Promise in javascript.我正在尝试构建自己的 Promise 以提高我对 javascript 中 Promise 的理解。 I'm currently stuck at the .then method and I'd like to ask: In the documentation for .then here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then , it says that the then method returns a Promise.我目前被困在.then方法上,我想问一下:在 .then 的文档中.then这里的https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise /then ,它表示then方法返回 Promise。 I'm having difficulties writing this because it seem like this.result is undefined .我在写这篇文章时遇到了困难,因为看起来this.resultundefined Why is that and how do I fix this?为什么会这样,我该如何解决?

Here's my code:这是我的代码:

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);
});

I think the core issue here is the following.我认为这里的核心问题如下。 then() typically gets processed in 2 different ways: then()通常以两种不同的方式处理:

  1. The promise is pending. promise 待定。 Store the callback(s) passed to then() and call those callbacks when the promise gets resolved later .存储传递给then()的回调,并在稍后解决 promise 时调用这些回调。
  2. The promise has a result (it resolved or rejected), in which case we'll call the callback passed to then as soon as possible. promise 有一个结果(它已解决或被拒绝),在这种情况下,我们将尽快调用传递给 then 的回调。

You're never handling case 1, so if the promise resolves after then() gets called, it won't work.您永远不会处理案例 1,因此如果 promisethen()被调用后解析,它将不起作用。

In addition, the sub promise you return from then() should itself resolve one the result of the callback passed to then() completes.此外,您从then()返回的子 promise 本身应该解决传递给then()的回调的结果完成。

If this sounds super confusing, it's because it's hard =) I would recommend to try and get your logic right first for just dealing with the callbacks in .then() , and don't return anything from .then() yet .如果这听起来非常令人困惑,那是因为这很难 =) 我建议先尝试让您的逻辑正确,以便仅处理.then .then()中的回调,并且不要从.then()返回任何内容。

I also made my own promise for the same reason.出于同样的原因,我还制作了自己的 promise。 It's pretty minimal, maybe it's helpful:它非常小,也许它有帮助:

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

Here is a sample program we expect to work with our promise ;这是我们希望与promise一起使用的示例程序; note the lowercase p -注意小写的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

As others commented there is a lot to fix in your code.正如其他人评论的那样,您的代码中有很多需要修复的地方。 But don't feel bad as Promise is not particularly easy to implement.但是不要感觉不好,因为 Promise 并不是特别容易实现。 Here's my first sketch of promise .这是我的第一个promise草图。 Note value , resolved , rejected are parameters of the constructor but they should be made private.注意valueresolvedrejected是构造函数的参数,但它们应该是私有的。 This can be done using a variety of techniques, but for sake of simplicity I left it this way for now.这可以使用多种技术来完成,但为了简单起见,我暂时保持这种方式。 The caller is only intended to pass the first argument, exec -调用者只打算传递第一个参数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)
  }
}

Like Promise, only p.then , p.catch should be available on promise objects.与 Promise 一样,在promise对象上应该只有p.thenp.catch可用。 We should prevent the user from calling p.resolve or p.reject directly, but for now it makes it easy to see how things work.我们应该阻止用户直接调用p.resolvep.reject ,但是现在它可以很容易地看到事情是如何工作的。 The class functions promise.resolve and promise.reject are analogous to Promise.resolve and Promise.reject . The class functions promise.resolve and promise.reject are analogous to Promise.resolve and Promise.reject .

Expand the snippet below to verify the result in your own browser -展开下面的代码片段以在您自己的浏览器中验证结果 -

 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)

I will come back tomorrow to add an example that demonstrates errors and answer any questions if you have them.明天我会回来添加一个示例来演示错误并回答任何问题(如果有的话)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM