Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

202
Views
¿Cómo se harían los getters y setters de JavaScript asíncronos?

Piense en cómo Rails, por ejemplo, le permite definir una propiedad asociada con otra:

 class Customer < ActiveRecord::Base has_many :orders end

Esto no configura una columna de base de datos para orders . En su lugar, crea un captador de orders , lo que nos permite hacer

 @orders = @customer.orders

Que va y obtiene los objetos de orders relacionados.

En JS, podemos hacer eso fácilmente con captadores:

 { name: "John", get orders() { // get the order stuff here } }

Pero Rails es sync , y en JS, si en nuestro ejemplo, como es razonable, vamos a la base de datos, lo estaríamos haciendo asíncrono .

¿Cómo crearíamos getters asíncronos (y setters, para el caso)?

¿Le devolveríamos una promesa que finalmente se resuelve?

 { 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; } }

que nos permitiría hacer

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

¿O lo haríamos con un estilo más angular, donde lo resolveríamos automáticamente en un valor?

En resumen, ¿cómo implementamos captadores asíncronos?

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

Las palabras clave de la función get y set parecen ser incompatibles con la palabra clave async . Sin embargo, dado que async / await es solo un envoltorio alrededor de Promise s, puede usar Promise para hacer que sus funciones sean " await -able".

Nota: Debería ser posible usar el método Object.defineProperty para asignar una función async a un definidor o captador.


adquiridor

Las promesas funcionan bien con captadores.

Aquí, estoy usando la función incorporada util.promisify() de Node.js 8 que convierte una devolución de llamada de estilo de nodo ("devolución de nodo") en una Promise en una sola línea. Esto hace que sea muy fácil escribir un captador capaz de await .

 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

Para los setters, se vuelve un poco raro.

Por supuesto, puede pasar una Promesa a un setter como argumento y hacer lo que sea por dentro, ya sea que espere a que se cumpla la Promesa o no.

Sin embargo, me imagino que un caso de uso más útil (¡el que me trajo aquí!) sería usar el setter y luego await que la operación se complete en cualquier contexto desde el que se haya utilizado el setter. Desafortunadamente, esto no es posible ya que el valor de retorno de la función setter se descarta .

 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!'); })();

En este ejemplo, Done! se imprime en la consola después 1 segundo y el Foo se imprime 2 segundos después de eso. Esto se debe a que await está esperando que se cumpla el valor promisedValue y nunca ve la Promise utilizada/generada dentro del setter.

over 4 years ago · Santiago Trujillo Report

0

En cuanto a captadores asíncronos, puede hacer algo como esto:

 const object = {}; Object.defineProperty(object, 'myProperty', { async get() { // Your awaited calls return /* Your value */; } });

Más bien, el problema surge cuando se trata de setters asincrónicos. Dado que la expresión a = b siempre produce b , no hay nada que se pueda hacer para evitar esto, es decir, ningún setter en el objeto que tenga la propiedad a puede anular este comportamiento.
Como también me topé con este problema, pude darme cuenta de que los setters asincrónicos eran literalmente imposibles. Entonces, me di cuenta de que tenía que elegir un diseño alternativo para usar en lugar de los setters asíncronos. Y luego se me ocurrió la siguiente sintaxis alternativa:

 console.log(await myObject.myProperty); // Get the value of the property asynchronously await myObject.myProperty(newValue); // Set the value of the property asynchronously

Lo tengo funcionando con el siguiente código,

 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; }

que devuelve un descriptor para una propiedad asíncrona, dado otro descriptor que puede definir algo que parece un setter asíncrono.

Puede utilizar el código anterior de la siguiente manera:

 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); } }) });

Una vez que haya configurado una propiedad asíncrona como la anterior, puede configurarla como ya se ilustra:

 (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'); })();
over 4 years ago · Santiago Trujillo Report

0

Lo siguiente permite setters asíncronos en controladores de proxy siguiendo la convención en la respuesta de Davide Cannizzo.

 var obj = new Proxy({}, asyncHandler({ async get (target, key, receiver) { await new Promise(a => setTimeout(a, 1000)) return target[key] }, async set (target, key, val, receiver) { await new Promise(a => setTimeout(a, 1000)) return target[key] = val } })) await obj.foo('bar') // set obj.foo = 'bar' asynchronously console.log(await obj.foo) // 'bar' function asyncHandler (h={}) { const getter = h.get const setter = h.set let handler = Object.assign({}, h) handler.set = () => false handler.get = (...args) => { let promise return new Proxy(()=>{}, { apply: (target, self, argv) => { return setter(args[0], args[1], argv[0], args[2]) }, get: (target, key, receiver) => { if (key == 'then' || key == 'catch') { return callback => { if (!promise) promise = getter(...args) return promise[key](callback) } } } }) } return handler }
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!