无法覆盖Promise类上的方法 - Promise.prototype.then调用不兼容的接收器undefined

时间:2018-01-29 10:09:09

标签: javascript node.js promise postman es6-promise

我正在尝试覆盖thencatchfinally函数。这是为了创建一个全局计数器并监视未决承诺。

代码需要执行Postman Sandbox,所以我不能使用任何NPM模块。我需要使用Native JS

执行此操作

以下是我正在努力解决的代码

_constructor = Promise.prototype.constructor
_then = Promise.prototype.then

Promise.prototype.constructor = (...args) => {
    console.log("Promise constructor called")
    let data = _constructor(...args)
    console.log("Promise constructor finished")
    return data;
}

Promise.prototype.then = (...args) => {
    console.log("then called")
    let data = _then.call(this, args)
    console.log("then finished")
    return data;
}

function test2(num) {
    let promise = new Promise((resolve, reject) => {
        if (num > 1) {
            setTimeout(()=> {
                resolve(num)
            }, 10)
        } else {
            reject(num);
        }
    });
    return promise
}

test2(10).then((num) => {
    console.log("Inside then")
    setTimeout(() => console.log("Promise has been resolved - " + num), 20);
})

但是当我运行这个时,我得到以下错误

    let data = _then.call(this, args)
                     ^

TypeError: Method Promise.prototype.then called on incompatible receiver #<Object>
    at Object.then (<anonymous>)
    at Promise.then.args (/Users/tarun.lalwani/Desktop/test/postman/temp.jsx:15:22)
    at Object.<anonymous> (/Users/tarun.lalwani/test/postman/temp.jsx:33:11)
    at Module._compile (module.js:660:30)
    at Object.Module._extensions..js (module.js:671:10)
    at Module.load (module.js:573:32)
    at tryModuleLoad (module.js:513:12)
    at Function.Module._load (module.js:505:3)
    at Function.Module.runMain (module.js:701:10)
    at startup (bootstrap_node.js:193:16)

我不确定这里有什么问题,或者这是否是正确的做法。

3 个答案:

答案 0 :(得分:3)

这有很多问题:

  • new Promise将调用Promise,而不是重写Promise.prototype.constructor
  • 箭头函数不是构造函数。在使用new进行调用时,它们会抛出。
  • 在没有_constructor的情况下拨打Promise(即内置new)将会抛出
  • 箭头功能不是方法。它们具有词法this值,而不是动态接收器。
  • 您想要apply args,而不是call,或使用点差语法

您可以通过正确使用functionReflect对象来解决这些问题,但我认为使用ES6子类化要简单得多:

Promise = class extends Promise {
    constructor(...args) {
        console.log("Promise constructor called")
        let data = super(...args)
        console.log("Promise constructor finished")
        return data;
    }
    then(...args) {
        console.log("then called")
        let data = super(...args)
        console.log("then finished")
        return data;
    }
};

当然,这里的任何内容实际上并不能确定承诺何时待决。

答案 1 :(得分:1)

  

在箭头函数中,这保留了封闭词汇的值   这是上下文。在全局代码中,它将被设置为全局对象

this in different contexts

您需要更改

Promise.prototype.constructor = (...args) => {
    console.log("Promise constructor called")
    let data = _constructor(...args)
    console.log("Promise constructor finished")
    return data;
}

Promise.prototype.then = (...args) => {
    console.log("then called")
    let data = _then.call(this, args)
    console.log("then finished")
    return data;
}

进入

Promise.prototype.constructor = function (...args) {
    console.log("Promise constructor called")
    let data = _constructor(...args)
    console.log("Promise constructor finished")
    return data;
}

Promise.prototype.then = function (...args) {
    console.log("then called")
    let data = _then.call(this, args)
    console.log("then finished")
    return data;
}

答案 2 :(得分:0)

@Tarun Lalwani,您不能覆盖上述promise构造函数,因为promise是一个类而不是一个函数。如@Bergi所述,您需要使用Reflect来拦截Promise构造函数。

这里的问题是ES6类(例如Promise)不可调用,这是ES5内置类(例如Array)的方式。编译器生成的发出的代码使用在ES6引擎中抛出的super.call。

此处的解决方法是使用Reflect.construct(如果存在)而不是调用。 Reflect.construct不是我们可以满足的条件,但是我们可以假设内置的Promise是否存在,Refelect.construct也存在。

https://github.com/Microsoft/TypeScript/issues/15202#issuecomment-297518643

在上面的链接中,提到了如何扩展构造函数。这样,您可以在致电console.log("Promise constructor called")

时打印new Promise()
相关问题