如何做异步 JavaScript 的 getter 和 setter? [英] How would one do async JavaScript getters and setters?

查看:18
本文介绍了如何做异步 JavaScript 的 getter 和 setter?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

想想 Rails,例如允许您定义一个与另一个相关联的属性:

class Customer 

这不会为orders 设置数据库列.相反,它为 orders 创建了一个 getter,它允许我们做

@orders = @customer.orders

去获取相关的orders对象.

在 JS 中,我们可以使用 getter 轻松做到这一点:

<代码>{姓名:约翰",获取订单(){//在这里获取订单内容}}

但是 Rails 是同步,而在 JS 中,如果在我们的示例中,按照合理的方式,我们要访问数据库,我们会异步.

我们将如何创建异步 getter(和 setter,就此而言)?

我们会返回一个最终得到解决的承诺吗?

<代码>{姓名:约翰",获取订单(){//创建一个承诺//db 和 promise 的伪代码...db.find("orders",{customer:"John"},function(err,data) {承诺.解决(数据);});回报承诺;}}

我们可以这样做

customer.orders.then(....);

或者我们会做更多的角度风格,我们会自动将它解析为一个值?

总而言之,我们如何实现异步 getter?

解决方案

getset 函数关键字似乎与 async 关键字.但是,由于 async/await 只是对 Promise s 的包装,您可以只使用 Promise 来制作你的函数await-able".

注意:应该可以使用 Object.defineProperty 方法将 async 函数分配给 setter 或 getter.><小时>

吸气剂

Promise 与 getter 配合得很好.

在这里,我使用了 Node.js 8 内置的 util.promisify() 函数,该函数将节点样式回调(nodeback")转换为 Promise单行.这使得编写一个 await-able 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(await bar.orders);})();

<小时>

二传手

对于二传手来说,这有点奇怪.

您当然可以将 Promise 作为参数传递给 setter 并在内部执行任何操作,无论您是否等待 Promise 完成.

然而,我想一个更有用的用例(把我带到这里的那个!)是使用 setter 然后 await 在 setter 的任何上下文中完成该操作从使用.不幸的是,这是不可能的,因为setter 函数的返回值被丢弃.

function makePromise(delay, val) {返回新的承诺(解决 => {setTimeout(() => resolve(val), delay);});}类设置测试{设置 foo(p) {返回 p.then(function(val) {//用 val 做一些需要时间的事情返回 makePromise(2000, val);}).then(console.log);}};var bar = new SetTest();var promiseValue = makePromise(1000, 'Foo');(异步函数(){等待(bar.foo = promiseValue);console.log('完成!');})();

在这个例子中,Done!1 秒后打印到控制台,Foo 被打印 2 秒后.这是因为 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 Promises, 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 awaiting 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屋!

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