异步JavaScript的getter和setter怎么办? [英] How would one do async JavaScript getters and setters?
问题描述
想想Rails的方式,例如允许您将一个属性定义为与另一个属性相关联:
Class客户<ActiveRecord :: Basehas_many:订单结尾
这不会为 orders
设置数据库列.相反,它为 orders
创建了一个吸气剂,使我们可以进行
@orders = @ customer.orders
去获取相关的 orders
对象.
在JS中,我们可以使用吸气剂轻松做到这一点:
{名称:约翰",获取订单(){//在此处获取订单商品}}
但是Rails是 sync ,并且在JS中,如果在我们的示例中,如果合理的话,我们要去数据库,我们将在 async 中进行操作./p>
我们将如何创建异步获取器(和设置器)?
我们会返回最终解决的诺言吗?
{名称:约翰",获取订单(){//创建一个承诺//db和promise的伪代码...db.find("orders",{customer:"John"}},function(err,data){promise.resolve(data);});回报承诺;}}
这将使我们能够做到
customer.orders.then(....);
还是我们会采用更具角度的样式,将其自动解析为值?
总而言之,我们如何实现异步获取器?
get
和 set
函数关键字似乎与 async
关键字.但是,由于 async
/ await
只是 Promise
的包装,因此您可以使用 Promise
进行您的函数"等待
-可以".
注意:应该可以使用 Object.defineProperty
方法将 async
函数分配给setter或getter. >
getter
承诺与吸气剂配合得很好.
在这里,我正在使用Node.js 8内置的 util.promisify()
函数,该函数将节点样式回调("nodeback")转换为 await
-getter变得非常容易.
var util = require('util');Foo类{获取订单(){return util.promisify(db.find)("orders",{customer:this.name});}};//我们不能在异步函数之外使用await(异步功能(){var bar = new Foo();bar.name ='约翰';//由于getter不能接受参数console.log(等待bar.orders);})();
设置器
对于二传手来说,这有点奇怪.
您当然可以将Promise传递给setter作为参数,并在内部做任何事情,无论您是否等待Promise的实现.
但是,我想一个更有用的用例(将我带到这里!)将用于setter,然后 await
使该操作在setter的任何上下文中完成从使用.不幸的是,这是不可能的,因为 setter函数的返回值已被丢弃.
function makePromise(delay,val){返回新的Promise(resolve => {setTimeout(()=> resolve(val),delay);});}类SetTest {设置foo(p){返回p.then(function(val){//用val做一些需要花费时间的事情返回makePromise(2000,val);}).then(console.log);}};var bar = new SetTest();var promisedValue = makePromise(1000,'Foo');(异步功能(){等待(bar.foo = promisedValue);console.log('完成!');})();
在此示例中,在 1
秒后将 Done!
打印到控制台,并在 2 中打印
Foo
代码>秒之后.这是因为 await
正在等待 promisedValue
履行,并且它从未看到setter内部使用/生成的 Promise
.
Think of how Rails, e.g. allows you to define a property as associated with another:
class Customer < ActiveRecord::Base
has_many :orders
end
This does not set up a database column for orders
. Instead, it creates a getter for orders
, which allows us to do
@orders = @customer.orders
Which goes and gets the related orders
objects.
In JS, we can easily do that with getters:
{
name: "John",
get orders() {
// get the order stuff here
}
}
But Rails is sync, and in JS, if in our example, as is reasonable, we are going to the database, we would be doing it async.
How would we create async getters (and setters, for that matter)?
Would we return a promise that eventually gets resolved?
{
name: "John",
get orders() {
// create a promise
// pseudo-code for db and promise...
db.find("orders",{customer:"John"},function(err,data) {
promise.resolve(data);
});
return promise;
}
}
which would allow us to do
customer.orders.then(....);
Or would we do it more angular-style, where we would automatically resolve it into a value?
To sum, how do we implement async getters?
The get
and set
function keywords seem to be incompatible with the async
keyword. However, since async
/await
is just a wrapper around Promise
s, you can just use a Promise
to make your functions "await
-able".
Note: It should be possible to use the Object.defineProperty
method to assign an async
function to a setter or getter.
getter
Promises work well with getters.
Here, I'm using the Node.js 8 builtin util.promisify()
function that converts a node style callback ("nodeback") to a Promise
in a single line. This makes it very easy to write an await
-able getter.
var util = require('util');
class Foo {
get orders() {
return util.promisify(db.find)("orders", {customer: this.name});
}
};
// We can't use await outside of an async function
(async function() {
var bar = new Foo();
bar.name = 'John'; // Since getters cannot take arguments
console.log(await bar.orders);
})();
setter
For setters, it gets a little weird.
You can of course pass a Promise to a setter as an argument and do whatever inside, whether you wait for the Promise to be fulfilled or not.
However, I imagine a more useful use-case (the one that brought me here!) would be to use to the setter and then await
ing that operation to be completed in whatever context the setter was used from. This unfortunately is not possible as the return value from the setter function is discarded.
function makePromise(delay, val) {
return new Promise(resolve => {
setTimeout(() => resolve(val), delay);
});
}
class SetTest {
set foo(p) {
return p.then(function(val) {
// Do something with val that takes time
return makePromise(2000, val);
}).then(console.log);
}
};
var bar = new SetTest();
var promisedValue = makePromise(1000, 'Foo');
(async function() {
await (bar.foo = promisedValue);
console.log('Done!');
})();
In this example, the Done!
is printed to the console after 1
second and the Foo
is printed 2
seconds after that. This is because the await
is waiting for promisedValue
to be fulfilled and it never sees the Promise
used/generated inside the setter.
这篇关于异步JavaScript的getter和setter怎么办?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!