【问题标题】:Simple Promise and Then implementation简单的 Promise 和 Then 实现
【发布时间】:2019-08-27 06:42:40
【问题描述】:

最近,我看到了一段在全栈开发人员面试中被问到的代码。 它涉及创建一个 Promise,候选人应在其中实施, 传递一个解析函数,然后链接 2 个。

我尝试非常天真地实现 Promise,只是为了使代码正常工作。 创建了一个接受解析器函数的 ctor, 创建了一个接受回调并返回 Promise 的 Then 函数, 并简单地调用解析器函数的回调。

class MyPromise {

    constructor(resolver) {
        this.resolver = resolver;
    }

    then(callback) {
        const result = new MyPromise(callback);
        this.resolver(callback);

        return result;
    }
}

promise = new MyPromise(
    (result) => {
        setTimeout(result(2), 500);
    });
promise.then(result => {
    console.log(result);
    return 2 * result;
}).then(result => console.log(result));

预期结果是 2,4 - 就像使用真正的 Promise 操作一样。 但我得到2,2。 我无法弄清楚如何获取第一个“then”的返回值并将其传递。

【问题讨论】:

  • 什么是r2...?代码的哪一部分是给你的?
  • 您的承诺概念不正确。看看Distilling how a promise works
  • 共享代码对您有用吗?甚至 setTimeout 也接受回调。您能否发布对您有用并产生 2,2 的代码
  • @trincot 我假设r2 应该是result
  • @AZ_ 就是这样。刚刚编辑了误入的“r2”东西

标签: javascript promise


【解决方案1】:

暗示这个r2实际上是结果参数。 您的代码的问题是您没有从 result(2) 中检索结果。第一个“then”被执行,打印 2,返回 4,但这 4 只是浪费了。 我写了一些带有同步函数的代码,只是为了演示如果你想得到这个 2,4 输出该怎么做:

class MyPromise {
    constructor(resolver) {
        this.resolver = resolver;
    }

    then(callback) {
          var res = callback(this.resolver());
        var result = new MyPromise(() => { return res; });

        return result;
    }
}

let promise = new MyPromise(
    () => {
        return 2;
    });

promise
.then(result => {
    console.log(result);
    return 2 * result;
})
.then(result => {
        console.log(result);
});

如果您希望解析器有点异步,您应该使用 Promises(因为可以检索在 setTimeout 内执行的函数的返回值,请参阅 here.

如果你不允许使用这些内置的 Promise,你可以用一些 dummy deferred object 自己编写它们并等待它们(setInterval)来解决(应该是基本相同的逻辑)。

【讨论】:

    【解决方案2】:

    您的问题有一些问题:

    • r2 变量未定义。我会假设 result 是有意的。
    • setTimeout 没有任何用处,因为您立即执行result(2)。我会假设 setTimeout(() => result(2), 500) 是有意的。

    如果在面试中真的给出了这样的代码,那么你的工作就是在做任何其他事情之前指出这两个问题。

    您尝试的一个问题是then 方法(即result)返回的承诺永远不会得到解决。您需要在this 承诺解决后立即解决它,并使用then 回调返回的值。

    另外,promise 构造函数参数是一个应该立即执行的函数。

    在以下解决方案中,与正确的 Promise 行为相比,进行了一些简化。

    • 它不会异步调用then 回调;
    • 不支持多个then 调用同一个promise;
    • 不提供拒绝路径;
    • 它不会阻止 promise 以不同的值解析两次;
    • 它不处理 then 回调返回承诺的特殊情况

    console.log("Wait for it...");
    
    class MyPromise {
        constructor(executor) {
            executor(result => this.resolve(result));
        }
        resolve(value) {
            this.value = value;
            this.broadcast();
        }
        then(onFulfilled) {
            const promise = new MyPromise(() => null);
            this.onFulfilled = onFulfilled;
            this.resolver = (result) => promise.resolve(result);
            this.broadcast();
            return promise;
        }
        broadcast() {
            if (this.onFulfilled && "value" in this) this.resolver(this.onFulfilled(this.value)); 
        }
    };
    
    // Code provided by interviewer, including two corrections
    promise = new MyPromise(
        (result) => {
            setTimeout(()=>result(2), 500); // don't execute result(2) immediately
        });
    promise.then(result => {
        console.log(result); // Changed r2 to result.
        return 2 * result;
    }).then(result => console.log(result));

    请注意输出中的 500 毫秒延迟,这是(更正后的)setTimeout 代码所期望的。

    我在this answerthis answer 中发布了一个完整的符合 Promises/A+ 的承诺实现与 cmets

    【讨论】:

    • 不错的答案。请注意,r2 错误现已在问题代码中得到纠正。
    【解决方案3】:

    这是用于创建 Promise 类的缩短代码,

    class MyPromise {
      constructor(executor) {
        this.callbacks = [];
    
        const resolve = res => {
          for (const { callback } of this.callbacks) {
            callback(res);
          }
        };
    
        executor(resolve);
      }
    
      then(callback) {
        return new MyPromise((resolve) => {
          const done = res => {
            resolve(callback(res));
          };
          this.callbacks.push({ callback: done });
        });
      }
    }
    
    
    promise = new MyPromise((resolve) => {
      setTimeout(() => resolve(2), 1000);
    });
    
    promise.then(result => {
      console.log(result);
      return 2 * result;
    }).then(result => console.log(result));

    【讨论】:

    • 为什么要让callbacks 成为一个对象数组?只需将函数本身放入
    • 您能否详细说明与实际实现相比,您的实现在哪些方面被缩短(不完整)?
    • @Bergi 我们当然可以这样做,但是稍后可以附加承诺以等待回调得到解决并有另一个布尔参数说 isFullfilled ,如果不是,回调可以被推入一个数组直到它没有,如果实现它可以直接调用该函数。
    • 不,这个功能应该在函数内部实现,callbacks数组不应该关心这个。
    • 当 MyPromise 构造函数回调立即调用 resolve 而不是 setTimeout 时,这不起作用。
    【解决方案4】:

    您的原始代码存在一些问题。值得注意的是,您仅在调用 then 方法时执行构造函数参数,并且实际上并没有链接“then”回调的输出。

    这是一个非常(非常!)基于调整您的示例的基本承诺实现。它也适用于在 promise 解决后调用 'then' 的情况(但如果 'then' 已经被调用,则不支持 - 不支持多个 then 块)。

    class MyPromise {
        constructor(resolver) {
            let thisPromise = this;
    
            let resolveFn = function(value){
                thisPromise.value = value; 
                thisPromise.resolved = true;
                if(typeof thisPromise.thenResolve === "function"){
                    thisPromise.thenResolve();
                }
                
            }
            if (typeof resolver === "function") {
                resolver(resolveFn);
            }
        }
        then(callback) {
            let thisPromise = this;
            thisPromise.thenFn = callback;
    
            return new MyPromise((resolve) =>{
                thisPromise.thenResolve = () => {
                    thisPromise.value = thisPromise.thenFn(thisPromise.value);
                    resolve(thisPromise.value);
                }
                //automatically resolve our intermediary promise if 
                //the parent promise is already resolved
                if(thisPromise.resolved){
                    thisPromise.thenResolve();
                }
            });
    
            
        }
    };
    
    //test code
    
    console.log("Waiting for Godot...");
    
    promise = new MyPromise((resolve) =>{
        setTimeout(()=>{
            resolve(2)
        },500);
    });
    
    
    promise.then((result) => {
        console.log(result);
        return 2 * result;
    }).then((result) => {
        console.log(result);
        return 2 * result;
    }).then((result) => {
        console.log(result)
    }); 

    【讨论】:

      【解决方案5】:

      很简单怎么样:

      const SimplePromise = function(cb) {
        cb(
          data =>
            (this.data = data) &&
            (this.thenCb || []).forEach(chain => (this.data = chain(this.data))),
          error =>
            (this.error = error) &&
            (this.catchCb || []).forEach(chain => (this.error = chain(this.error)))
        );
        this.then = thenCb =>
          (this.thenCb = [...(this.thenCb || []), thenCb]) && this;
        this.catch = catchCb =>
          (this.catchCb = [...(this.catchCb || []), catchCb]) && this;
      };
      

      此处示例:https://codesandbox.io/s/0q1qr8mpxn

      【讨论】:

      • /very simple/ 为简洁而自豪,但它是如此纤薄,实用性非常有限。没有然后特别是链接。
      • 而不是返回 this 然后你必须返回相同的函数和回调,否则它不支持链接;
      猜你喜欢
      • 1970-01-01
      • 2021-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-16
      • 1970-01-01
      • 1970-01-01
      • 2018-04-02
      相关资源
      最近更新 更多