如何做异步JavaScript getter和setter?

dei*_*tch 17 javascript promise

想想Rails如何允许您将属性定义为与另一个属性相关联:

class Customer < ActiveRecord::Base
  has_many :orders
end
Run Code Online (Sandbox Code Playgroud)

这不会为其设置数据库列orders.相反,它创造了一个吸气剂orders,这使我们能够做到

@orders = @customer.orders
Run Code Online (Sandbox Code Playgroud)

哪个去获取相关orders对象.

在JS中,我们可以使用getter轻松实现:

{
   name: "John",
   get orders() {
     // get the order stuff here
   }
}
Run Code Online (Sandbox Code Playgroud)

但是Rails是同步的,而在JS中,如果在我们的例子中,合理的话,我们将进入数据库,我们将把它做为异步.

我们如何创建异步getter(以及setter)?

我们会回复最终得到解决的承诺吗?

{
   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;
   }
}
Run Code Online (Sandbox Code Playgroud)

这将允许我们这样做

customer.orders.then(....);
Run Code Online (Sandbox Code Playgroud)

或者我们会做更多角度风格,我们会自动将其解析为值吗?

总之,我们如何实现异步吸气剂?

Cam*_*ind 9

getset功能的关键字似乎有不兼容的async关键字.但是,因为async/ await只是Promises 的包装,你可以使用a Promise来使你的函数" await-able".

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


吸气

承诺与吸气剂配合良好.

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

二传手

对于制定者来说,它有点奇怪.

您当然可以将Promise作为参数传递给setter,并在内部做任何事情,无论您是否等待Promise得到满足.

但是,我想一个更有用的用例(将我带到这里的那个!)将用于setter,然后await在任何使用setter的上下文中完成该操作.遗憾的是,这是不可能的,因为丢弃了来自setter函数的返回值.

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!');
})();
Run Code Online (Sandbox Code Playgroud)

在此示例中,Done!1第二个之后将其打印到控制台,然后在几秒钟之后Foo打印2.这是因为await等待promisedValue实现并且它永远不会看到Promisesetter内部使用/生成.

  • TMHO,getter 确实被正确地承诺了,但我认为 setter 的例子并不现实:如果提供的值是一个承诺 - 首先取消承诺,然后再调用集合......非常简单;但是,如果我们讨论的是 set 方法*内部*的值设置包含一些异步工作的过程,那就是另一回事了。然后,我们最好用异步嵌套函数包装逻辑并返回其返回值(这是一个承诺)。 (2认同)

小智 -5

这是实现获取订单功能的方法

function get(name) {
    return new Promise(function(resolve, reject) {
        db.find("orders", {customer: name}, function(err, data) {
             if (err) reject(err);
             else resolve(data);
        });
    });
}
Run Code Online (Sandbox Code Playgroud)

你可以像这样调用这个函数

customer.get("John").then(data => {
    // Process data here...
}).catch(err => {
    // Process error here...
});
Run Code Online (Sandbox Code Playgroud)