在 JavaScript 中扩展 Promise [英] Extending a Promise in javascript

查看:22
本文介绍了在 JavaScript 中扩展 Promise的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习 JavaScript 中的类和继承.我认为以下是扩展现有对象的相当标准的方式,因为我从 关于 Object.create 的 MDN 文档

I'm learning about classes and inheritance in javascript. I thought that the following is a fairly standard way of extending an existing object as I got the style from the MDN docs on Object.create

我期待看到好的"然后是耶!你好'在控制台中,但我却出现了这个错误:

I was expecting to see 'ok' and then 'Yay! Hello' in the console, but instead I go this error:

Uncaught TypeError: #<MyPromise> is not a promise
at new MyPromise (<anonymous>:5:17)
at <anonymous>:19:6

看起来 Promise 构造函数正在抛出异常,因为它可以告诉我给它初始化的对象不是一个简单的 Promise.

It looks like the Promise constructor is throwing an exception because it can tell that the object I've given it to initialise isn't a straightforward Promise.

我希望 Promise 构造函数将我的对象初始化为 Promise 对象,这样我就可以扩展该类.他们为什么不编写 Promise 构造函数来使用这种常见模式?难道我做错了什么?干杯看看!

I want the Promise constructor to initialise my object as if it was a Promise object, so I can then extend the class. Why wouldn't they write the Promise constructor to work with this common pattern? Am I doing something wrong? Cheers for taking a look!

MyPromise = function(message, ok) {
    var myPromise = this;
    this.message = message;
    this.ok = ok;
    Promise.call(this, function(resolve, reject) {
        if(this.ok) {
            console.log('ok');
            resolve(myPromise.message);
        } else {
            console.log('not ok');
            reject(myPromise.message);
        }   
    }); 
};  

MyPromise.prototype = Object.create(Promise.prototype);
MyPromise.prototype.constructor = MyPromise;

(new MyPromise('Hello', true))
    .then(function(response) {console.log('Yay! ' + response);})
    .except(function(error) {console.log('Aww! ' + error);});

我最初试图制作一个您可以使用的 BatchAjax 类:

I was originally trying to make a BatchAjax class that you could use like:

(new BatchAjax([query1, query2]))
    .then(function(response) {console.log('Fires when all queries are complete.');}); 

真的只是有点好玩.

推荐答案

原生 Promise 类(如 ErrorArray)不能被使用旧的 ES5 风格的子类化机制正确子类化.

The native Promise class (like Error and Array) cannot be correctly subclassed with the old ES5-style mechanism for subclassing.

子类Promise的正确方法是通过class语法:

The correct way to subclass Promise is through class syntax:

class MyPromise extends Promise {
}

示例:

class MyPromise extends Promise {
    myMethod() {
        return this.then(str => str.toUpperCase());
    }
}

// Usage example 1
MyPromise.resolve("it works")
    .myMethod()
    .then(result => console.log(result))
    .catch(error => console.error(error));
    
// Usage example 2
new MyPromise((resolve, reject) => {
    if (Math.random() < 0.5) {
        resolve("it works");
    } else {
        reject(new Error("promise rejected; it does this half the time just to show that part working"));
    }
})
    .myMethod()
    .then(result => console.log(result))
    .catch(error => console.error(error));

如果您的目标是在没有 class 的情况下做到这一点,主要使用 ES5 级别的功能,您可以通过 Reflect.construct.请注意,Reflect.construct 是 ES2015 的一个特性,就像 class,但你似乎更喜欢 ES5 风格的创建类.

If it's your goal to do that without class, using mostly ES5-level features, you can via Reflect.construct. Note that Reflect.construct is an ES2015 feature, like class, but you seem to prefer the ES5 style of creating classes.

您可以这样做:

// Create a constructor that uses `Promise` as its super and does the `super` call
// via `Reflect.construct`
const MyPromise = function(executor) {
    return Reflect.construct(Promise, [executor], MyPromise);
};
// Make `MyPromise` inherit statics from `Promise`
Object.setPrototypeOf(MyPromise, Promise);
// Create the prototype, add methods to it
MyPromise.prototype = Object.create(Promise.prototype);
MyPromise.prototype.constructor = MyPromise;
MyPromise.prototype.myMethod = function() {
    return this.then(str => str.toUpperCase());
};

然后像Promise一样使用:

MyPromise.resolve("it works")
    .myMethod()
    .then(result => console.log(result))
    .catch(error => console.error(error));

new MyPromise(resolve => resolve("it works"))
    .myMethod()
    .then(result => console.log(result))
    .catch(error => console.error(error));

现场示例:

// Create a constructor that uses `Promise` as its super and does the `super` call
// via `Reflect.construct`
const MyPromise = function(executor) {
    return Reflect.construct(Promise, [executor], MyPromise);
};
// Make `MyPromise` inherit statics from `Promise`
Object.setPrototypeOf(MyPromise, Promise);
// Create the prototype, add methods to it
MyPromise.prototype = Object.create(Promise.prototype);
MyPromise.prototype.constructor = MyPromise;
MyPromise.prototype.myMethod = function() {
    return this.then(str => str.toUpperCase());
};

// Usage example 1
MyPromise.resolve("it works")
    .myMethod()
    .then(result => console.log(result))
    .catch(error => console.error(error));
    
// Usage example 2
new MyPromise((resolve, reject) => {
    if (Math.random() < 0.5) {
        resolve("it works");
    } else {
        reject(new Error("promise rejected; it does this half the time just to show that part working"));
    }
})
    .myMethod()
    .then(result => console.log(result))
    .catch(error => console.error(error));

如果你想避免改变MyPromise的原型,你可以把静态属性复制过来,但不是一回事:

If you want to avoid changing the prototype of MyPromise, you can copy the static properties over, but it's not quite the same thing:

// Create a constructor that uses `Promise` as its super and does the `super` call
// via `Reflect.construct`
const MyPromise = function(executor) {
    return Reflect.construct(Promise, [executor], MyPromise);
};
// Assign the statics (`resolve`, `reject`, etc.) to the new constructor
Object.assign(
    MyPromise,
    Object.fromEntries(
        Reflect.ownKeys(Promise)
            .filter(key => key !== "length" && key !== "name")
            .map(key => [key, Promise[key]])
    )
);
// Create the prototype, add methods to it
MyPromise.prototype = Object.create(Promise.prototype);
MyPromise.prototype.constructor = MyPromise;
MyPromise.prototype.myMethod = function() {
    return this.then(str => str.toUpperCase());
};

使用它当然是一样的.

现场示例:

// Create a constructor that uses `Promise` as its super and does the `super` call
// via `Reflect.construct`
const MyPromise = function(executor) {
    return Reflect.construct(Promise, [executor], MyPromise);
};
// Assign the statics (`resolve`, `reject`, etc.) to the new constructor
Object.assign(
    MyPromise,
    Object.fromEntries(
        Reflect.ownKeys(Promise)
            .filter(key => key !== "length" && key !== "name")
            .map(key => [key, Promise[key]])
    )
);
// Create the prototype, add methods to it
MyPromise.prototype = Object.create(Promise.prototype);
MyPromise.prototype.constructor = MyPromise;
MyPromise.prototype.myMethod = function() {
    return this.then(str => str.toUpperCase());
};

// Usage example 1
MyPromise.resolve("it works")
    .myMethod()
    .then(result => console.log(result))
    .catch(error => console.error(error));
    
// Usage example 2
new MyPromise((resolve, reject) => {
    if (Math.random() < 0.5) {
        resolve("it works");
    } else {
        reject(new Error("promise rejected; it does this half the time just to show that part working"));
    }
})
    .myMethod()
    .then(result => console.log(result))
    .catch(error => console.error(error));

这篇关于在 JavaScript 中扩展 Promise的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆