Think of how Rails, e.g. allows you to define a property as associated with another:
class Customer < ActiveRecord::Base
has_many :orders
end
As for asynchronous getters, you may just do something like this:
const object = {};
Object.defineProperty(object, 'myProperty', {
async get() {
// Your awaited calls
return /* Your value */;
}
});
Rather, the problem arises when it comes to asynchronous setters.
Since the expression a = b
always produce b
, there is nothing one can do to avoid this, i.e. no setter in the object holding the property a
can override this behavior.
Since I stumbled upon this problem as well, I could figure out asynchronous setters were literally impossible. So, I realized I had to choose an alternative design for use in place of async setters. And then I came up with the following alternative syntax:
console.log(await myObject.myProperty); // Get the value of the property asynchronously
await myObject.myProperty(newValue); // Set the value of the property asynchronously
I got it working with the following code,
function asyncProperty(descriptor) {
const newDescriptor = Object.assign({}, descriptor);
delete newDescriptor.set;
let promise;
function addListener(key) {
return callback => (promise || (promise = descriptor.get()))[key](callback);
}
newDescriptor.get = () => new Proxy(descriptor.set, {
has(target, key) {
return Reflect.has(target, key) || key === 'then' || key === 'catch';
},
get(target, key) {
if (key === 'then' || key === 'catch')
return addListener(key);
return Reflect.get(target, key);
}
});
return newDescriptor;
}
which returns a descriptor for an asynchronous property, given another descriptor that is allowed to define something that looks like an asynchronous setter.
You can use the above code as follows:
function time(millis) {
return new Promise(resolve => setTimeout(resolve, millis));
}
const object = Object.create({}, {
myProperty: asyncProperty({
async get() {
await time(1000);
return 'My value';
},
async set(value) {
await time(5000);
console.log('new value is', value);
}
})
});
Once you've set up with an asynchronous property like the above, you can set it as already illustrated:
(async function() {
console.log('getting...');
console.log('value from getter is', await object.myProperty);
console.log('setting...');
await object.myProperty('My new value');
console.log('done');
})();