这是一个可继承的承诺吗?

时间:2017-01-23 21:39:41

标签: javascript inheritance ecmascript-6 promise prototype

只是为了好玩/学习我想扩展Promise,并通过stackoverflow上令人难以置信的知识人员发现,无法使用标准的旧语法。但我还是想,所以我想创建自己的IPromise类,它组成一个Promise对象,并允许其他人使用旧的非ES6语法继承它。

我想知道这个实现与内置Promise可直接继承的Universe有何不同,如果有人有洞察力,为什么内置Promise的实现者不允许继承旧语法。

这是我的可扩展/可继承的IPromise类:

// Inheritable Promise
IPromise = function(executor) {
    this.promise = new Promise(executor);
};
IPromise.prototype = Object.create(Promise.prototype);
IPromise.prototype.constructor = IPromise;
IPromise.prototype.catch = function(fail) {
    return this.promise.catch(fail);
}
IPromise.prototype.then = function(success, fail) {
    return this.promise.then(success, fail);
};  

// Usage
// No different to builtin Promsise
(new IPromise(function(resolve, reject) { return resolve(true); }))
    .then(function(response) {
        console.log('IPromise then is like Promise then', response);
    })
    .catch(function(error) {
        console.log('IPromise catch is like Promise catch', error);
    });

这是一个为批量ajax扩展它的示例,它等待所有请求完成,无论它们是否有任何失败。与内置功能略有不同。

// Inheriting
// You can inherit from IPromise like you would any normal class.
BatchAjax = function(queries) {
    var batchAjax = this;
    this.queries = queries;
    this.responses = []; 
    this.errorCount = 0; 
    IPromise.call(this, function(resolve, reject) { 
        batchAjax.executor(resolve, reject);
    });
};
BatchAjax.prototype = Object.create(IPromise.prototype);
BatchAjax.prototype.constructor = BatchAjax;
BatchAjax.prototype.executor = function(resolve, reject) {
    var batchAjax = this;
    $.each(this.queries, function(index) {
        var query = this;
        query.success = function (result) { 
            batchAjax.processResult(result, index, resolve, reject);
        };
        query.error = function (jqXhr, textStatus, errorThrown) {
            batchAjax.errorCount++;
            var result = {
                jqXhr: jqXhr, textStatus: textStatus, errorThrown: errorThrown
            };
            batchAjax.processResult(result, index, resolve, reject);
        };
        $.ajax(query);
    });
};
BatchAjax.prototype.processResult = function(result, index, resolve, reject) {
    this.responses[index] = result;
    if (this.responses.length === this.queries.length) {
        if (this.errorCount === 0) {
            resolve(this.responses);
        } else {
            reject(this.responses);
        }
    }
};

// Usage
// Inheriting from IPromise is boring, which is good.
var baseUrl = 'https://jsonplaceholder.typicode.com';
(new BatchAjax([{url: baseUrl + '/todos/4'}, {url: baseUrl + '/todos/5'}]))
    .then(function(response) {console.log('Yay! ', response);})
    .catch(function(error) {console.log('Aww! ', error);});

请记住,我只是在学习,这并不意味着有用,只是有趣。但是随意给予残酷的批评,我对这是一个愚蠢的事情这个想法持开放态度。)

干得好看,对所有代码感到抱歉!

编辑:这是我最初试图延长承诺的问题:Extending a Promise in javascript。它似乎不适用于旧语法,因为Promise构造函数如果注意到它正在初始化一些不是Promise的东西(我认为),则抛出一个Type错误。

edit2:jfriend00的评论突出了一些有趣的内容。 IPromise.then应该返回什么?目前它只是一个承诺,但它应该是一个IPromise吗?

IPromise.prototype.then = function(success, fail) {
    this.promise.then(success, fail);
    return new IPromise(whatGoesHere?);
};

或者任何类继承自它的实例。

IPromise.prototype.then = function(success, fail) {
    this.promise.then(success, fail);
    return new this.constructor(whatGoesHere?);
};

或者它可以归还吗?

IPromise.prototype.then = function(success, fail) {
    this.promise.then(success, fail);
    return this;
};

我知道Promise.then返回一个Promise,但我不知道Promise是如何设置或预期的。这就是为什么我避免了这个问题,只是从this.promise.then返回了Promise。还有其他合理的解决方案吗?

2 个答案:

答案 0 :(得分:2)

是的,您的IPromise行为与真实Promise大致相同。但是,例如,你不能在它们上调用原生的promise方法:

var p = new Promise(function(resolve) { return resolve(true); });
var ip = new IPromise(function(resolve) { return resolve(true); });
Promise.prototype.then.call(p, v => console.log(v));
Promise.prototype.then.call(ip, v => console.log(v)); // TypeError

如果您希望IPromise个实例成为真正的承诺,则必须由Promise进行初始化。该构造函数添加了一些内部插槽,如[[PromiseState]],您无法模拟。但是Promise创建的承诺继承自Promise.prototype,而在ES6之前,在创建对象之后没有标准的方法将[[Prototype]]更改为IPromise.prototype

使用ES6课程,

class IPromise extends Promise {
  // You can add your own methods here
}

答案 1 :(得分:0)

以下是jfriend00的评论建议。

当你链接IPromises时,你不会在链接后获得一个IPromise对象,因为你的IPromise.prototype.then()只返回一个普通的Promise return this.promise.then(success, fail);

  

我:应该IPromise.then只是做:

this.promise.then(success, fail);
     

然后其中一个?

return new IPromise(whatGoesHere?);
return new this.constructor(whatGoesHere?);
return this;

这是延长承诺真的很麻烦的原因之一。基础结构本身会在每次.then()调用时创建新的promise,并且在没有支持子类化的底层基础结构的情况下,不提供一种简单的方法来挂钩。如果你看here某些环境中存在支持。但是,我总是发现我可以通过其他方式解决我的问题。所以,我不会试图破解我自己的子类,因为它似乎可能有漏洞。

回到我身边(tobuslieven)现在又说话了。我同意这一点,但是如果我看到机会的话,我仍然会记住这个课程并使用它。我认为返回Promise而不是IPromise是可行的,能够像这样扩展Promises真的很有趣。

所以我的回答是肯定的,可能已经足够好了,值得在某个地方使用。