2015-03-01 11 views
8

Pomyśl o tym, jak Rails, np. pozwala zdefiniować jako właściwość związaną z innego:Jak zrobić asynchronizatory i setery JavaScript?

class Customer < ActiveRecord::Base 
    has_many :orders 
end 

nie utworzenia kolumny bazy danych dla orders. Zamiast tego tworzy getter dla orders, która pozwala nam robić

@orders = @customer.orders 

który jedzie i dostaje powiązanych orders obiektów.

W JS, możemy łatwo zrobić z pobierające:

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

Ale szyn jest sync oraz w JS, jeśli w naszym przykładzie jest to uzasadnione, jedziemy do bazy danych, my będzie to robić async.

Jak moglibyśmy stworzyć asynchroniczne obiekty pobierające (i setery)?

Czy zwrócimy obietnicę, która ostatecznie zostanie rozwiązana?

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

który pozwoli nam zrobić

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

Albo zrobimy to bardziej kanciasty styl, w którym będziemy automatycznie rozwiązać go na wartości?

Podsumowując, w jaki sposób zaimplementować moduły pobierające asynchroniczne?

+1

Nie mogę wymyślić innego sposobu niż zwrot obietnicy. –

+0

Generatory z 'yield' może? – elclanrs

+0

@elclanrs: AFAIK a getter nie może być generatorem. –

Odpowiedz

-1

Oto w jaki sposób można realizować swoje zamówienia get funkcjonować

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

Można wywołać tę funkcję jak

customer.get("John").then(data => { 
    // Process data here... 
}).catch(err => { 
    // Process error here... 
}); 
+0

Nie korzysta z deskryptora właściwości get/set - byłoby to po prostu dodanie własnej metody do obiektu, który jest podobny w pewien sposób, ale inny. – Femtosecond

2

W get i set funkcyjne słowa kluczowe wydają się być niezgodne ze słowem kluczowym async. Jednak, ponieważ async/await jest tylko opakowaniem wokół Promise s, możesz po prostu użyć Promise, aby twoje funkcje były "dostępne".

Uwaga: Powinno być możliwe użycie metody Object.defineProperty do przypisania funkcji async do nastawnika lub odbiorcy.


getter

Obietnice dobrze współpracować z pobierające.

Tutaj używam funkcji wbudowanej Node.js 8 util.promisify(), która przekształca wywołanie zwrotne stylu węzła ("nodeback") na Promise w jednej linii. To sprawia, że ​​bardzo łatwo można zapisać program pobierający o wartości 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); 
})(); 

seter

Dla ustawiaczy, robi się trochę dziwne.

Możesz oczywiście przekazać obietnicę jako argument i zrobić wszystko, co wewnątrz, bez względu na to, czy czekasz na spełnienie obietnicy, czy nie.

Jednak wyobrażam sobie, że bardziej użytecznym przypadkiem użycia (ten, który mnie tu przywiódł!) Byłoby użycie do ustawiacza, a następnie await do wykonania tej operacji w dowolnym kontekście, w którym został użyty setter. Niestety nie jest to możliwe, ponieważ wartość zwracana z funkcji ustawiającej jest odrzucana.

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

W tym przykładzie Done! jest drukowany na konsoli po 1 sekund i Foo jest drukowany 2 sekund później. Dzieje się tak dlatego, że await czeka na spełnienie promisedValue i nigdy nie widzi, że Promise został użyty/wygenerowany wewnątrz setera.

Powiązane problemy