NEWS
getState ohne/mit await
-
@hub01 sagte: getState arbeitet asynchron?
Nein, getState() ohne Callback-Funktion arbeitet synchron. Der Zustand wird aus dem Puffer der Javascript-Instanz geholt.
-
@paul53
ok, dann habe ich das falsch verstanden,
vl. mit setState verwechselt, dort ist es so, oder?
Das heißt, getState liefert den aktuellen Wert (aus dem Puffer) bevor die nächsten Befehle abgearbeitet werden.Was ist der Unterschied zwischen Daten aus dem Puffer oder aus einem Datenpunkt?
-
@hub01 sagte: mit setState verwechselt, dort ist es so, oder?
Ja, setState() arbeitet asynchron.
@hub01 sagte in getState ohne/mit await:
Was ist der Unterschied zwischen Daten aus dem Puffer oder aus einem Datenpunkt?
await getStateAsync() liefert die Daten direkt aus dem js-controller.
In der asynchronen Version von getState(id, callback) werden die Daten ebenfalls direkt aus dem js-controller geholt und an die Callback-Funktion übergeben. -
@paul53 sagte in getState ohne/mit await:
getState() ohne Callback-Funktion arbeitet synchron. Der Zustand wird aus dem Puffer der Javascript-Instanz geholt.
@paul53 sagte in getState ohne/mit await:
await getStateAsync() liefert die Daten direkt aus dem js-controller.
Was ist der Unterschied der beiden Varianten?
-
@hub01 sagte: Was ist der Unterschied der beiden Varianten?
Das Holen direkt vom js-controller ist aufwändiger. Dafür kann man den Puffer in den Einstellungen der Javascript-Instanz deaktivieren, was aber die Verwendung der synchronen Version von getState(id) und getObject(id) ausschließt.
-
@paul53 sagte in getState ohne/mit await:
Das Holen direkt vom js-controller ist aufwändiger. Dafür kann man den Puffer in den Einstellungen der Javascript-Instanz deaktivieren, was aber die Verwendung der synchronen Version von getState(id) und getObject(id) ausschließt.
ist das wirklich so?
dann könnte es ja einen inkonsistenten Datenstand geben, je nachdem welche Funktion verwendet wird.Meinem Wissen nach steckt da immer die gleiche eine Funktion dahinter:
getState ohne Callback, eigentlich nicht sinnvoll. Wahrscheinlichkeit aus Gründen der Gleichförmigkeit der Funktionen so beibehalten
getState mit Callback, Callback wird aufgerufen, wenn Wert vom Backend (Memory,Redis,jsonl) zurückkehrt.
https://github.com/ioBroker/ioBroker.js-controller/blob/6ade4045339082a9408e17e0871ad26dc41206ca/packages/adapter/src/lib/adapter/adapter.ts#L9018getStateAsync ist eigentlich nur mit der Methode promisify ein angepasstes getState
https://github.com/ioBroker/ioBroker.js-controller/blob/6ade4045339082a9408e17e0871ad26dc41206ca/packages/adapter/src/lib/adapter/adapter.ts#L1224Die obigen Links sind Verweise auf den Source des iobroker Adapter-Frameworks. Der javascript-Adapter verwendet diese Funktionen, hat da aber noch ein wenig Logik dazwischen, was aber an der Grundfunktionsweise nichts ändert.
-
@oliverio sagte: dann könnte es ja einen inkonsistenten Datenstand geben, je nachdem welche Funktion verwendet wird.
setState() schreibt in den eigenen Puffer und übergibt auch den Zustand an den js-controller.
@oliverio sagte in getState ohne/mit await:
getState ohne Callback, eigentlich nicht sinnvoll.
getState(id) des Javascript-Adapters ist nicht getState() des js-controllers.
Im Javascript-Adapter wird geprüft, ob eine Callback-Funktion übergeben wurde. Falls nicht, wird der Zustand aus dem eigenen Puffer zurück gegeben. -
@oliverio sagte in getState ohne/mit await:
@paul53 sagte in getState ohne/mit await:
Das Holen direkt vom js-controller ist aufwändiger. Dafür kann man den Puffer in den Einstellungen der Javascript-Instanz deaktivieren, was aber die Verwendung der synchronen Version von getState(id) und getObject(id) ausschließt.
ist das wirklich so?
dann könnte es ja einen inkonsistenten Datenstand geben, je nachdem welche Funktion verwendet wird.Ob inkonsistent weiß ich nicht, aber bei planlosem Mischen kann dann sowas raus kommen:
dp: 0_userdata.0.testNumber - schreibe: 6564 lese: 7161
async function main() { const num = Math.round(Math.random() *10000) setState('0_userdata.0.testNumber', num); const val = (await getStateAsync('0_userdata.0.testNumber')).val log( 'dp: 0_userdata.0.testNumber - schreibe: ' + num + ' lese: ' + val); } main()
Bei
extendObjectAsync()
kann man nicht direkt im Scriptadapter mit dem state weiterarbeiten da der im Adapter noch nicht existiert - da ist dann Async angesagt - oder halt sleep(50) oder so. (createStateAsync hatte früher auch probleme damin, aber nutze ich nicht mehr, daher keine ahnung) -
@ticaki sagte: kann dann sowas raus kommen:
setState() war noch nicht fertig.
-
@paul53 sagte in getState ohne/mit await:
@hub01 sagte: Was ist der Unterschied der beiden Varianten?
Das Holen direkt vom js-controller ist aufwändiger. Dafür kann man den Puffer in den Einstellungen der Javascript-Instanz deaktivieren, was aber die Verwendung der synchronen Version von getState(id) und getObject(id) ausschließt.
Da gehen mir wohl noch ein paar Grundkenntnisse und Zusammenhänge ab.
Welchen Weg nehmen die Daten?
Datenpunkt, Javascript-Adapter, Puffer, js-controller, Variable im Skript, … -
@hub01 sagte in getState ohne/mit await:
Datenpunkt, Javascript-Adapter, Puffer, js-controller, Variable im Skript, …
- alle datenpunkte werden je nach konfiguration entweder in der jsonl oder in redis gespeichert.
- nur der js-controller arbeitet mit diesem backend.
- der js-controller stellt allen adaptern standardfunktionen zum zugriff auf diesen daten bereit: getState,setState.
- der javascript baut für sich noch diesen puffer auf und spiegelt für die skripte mehr oder weniger diese befehle getState,setState, die die Skripte nutzen können um Daten in Variablen zu schreiben oder aus Variablen in einen Datenpunkt zu schreiben
-
@hub01 sagte: Welchen Weg nehmen die Daten?
Der Zustand eines Datenpunktes existiert im Original im js-controller. Manche Adapter-Instanzen (Javascript, Admin) haben eigene Puffer, die ein Abbild aller Datenpunktzustände und Objekte enthalten. Das synchrone getState(id) holt den Zustand eines DP aus dem Zustände-Puffer der Javascript-Instanz. Das synchrone getObject(id) holt sich das adressierte Objekt aus dem Objekte-Puffer.
-
@oliverio sagte: alle datenpunkte werden je nach konfiguration entweder in der jsonl oder in redis gespeichert.
Im laufenden Betrieb werden die Zustände (states) und Objekte nur in die DB geschrieben, damit sie bei Neustart von ioBroker von dort wieder hergestellt werden können.
-
ich habe mal versucht, das Ganze aus den bisherigen Infos zu erfassen.
Liege ich da richtig?
-> der Zugriff auf die js-controller-Datenbank erfolgt immer asynchron
-> der Zugriff auf den js-Adapter-Puffer erfolgt immer synchronUnklar ist mir noch der Puffer.
-> welche Daten werden dort gehalten?
-> wie/wann erfolgt ein Abgleich mit der Datenbank? -
@hub01 sagte: wie/wann erfolgt ein Abgleich mit der Datenbank?
Der JS-Adapter abonniert alle Zustände beim js-controller und wird so synchron gehalten.
@hub01 sagte in getState ohne/mit await:
welche Daten werden dort gehalten?
Alle Objekte und Zustände des js-controllers.
@hub01 sagte in getState ohne/mit await:
Liege ich da richtig?
-> der Zugriff auf die js-controller-Datenbank erfolgt immer asynchron
-> der Zugriff auf den js-Adapter-Puffer erfolgt immer synchronNein.
setState() schreibt immer in den eigenen Puffer (wenn vorhanden) und in den js-controller und arbeitet immer asynchron.
await getStateAsync(id) liefert den Zustand synchron aus dem js-controller. -
Wenn "Do not subscribe all states on start" nicht aktiv ist (default), dann benötigt man keine callback bzw await für getState. Das ist dann immer synchron.
-
@fernetmenta sagte: Wenn "Do not subscribe all states on start" nicht aktiv ist (default), dann benötigt man keine callback
Ja, dann wird gepuffert.
-
@paul53
korrigierte Fassung,
nur gültig, wenn beim Start alle Zustände abonniert werden (mit Puffer)
-
@hub01 Das stimmt so nicht ganz, wenn ich den code vom javascript adapter richtig gelesen habe. Wenn alle Zustände aboniert sind, holt der Adapter die Werte immer aus dem Puffer. Es ist egal welchen Befehl man verwendet.
-
@fernetmenta sagte: Wenn alle Zustände aboniert sind, holt der Adapter die Werte immer aus dem Puffer. Es ist egal welchen Befehl man verwendet.
Nein. Auszug "sandbox.js" (Zeile 2479 ff.):
getState: function (id, callback) { if (typeof id !== 'string') { sandbox.log(`getState has been called with id of type "${typeof id}" but expects a string`, 'error'); return undefined; } if (typeof callback === 'function') { if (!id.includes('.')) { adapter.getState(id, (err, state) => callback(err, context.convertBackStringifiedValues(id, state)), ); } else { adapter.getForeignState(id, (err, state) => callback(err, context.convertBackStringifiedValues(id, state)), ); } } else { if (adapter.config.subscribe) { sandbox.log( 'The "getState" method cannot be used synchronously, because the adapter setting "Do not subscribe to all states on start" is enabled.', 'error', );
getStateAsync(id):
getStateAsync: async function (id) { let state; if (id.includes('.')) { state = await adapter.getForeignStateAsync(id); } else { state = await adapter.getStateAsync(id); } return context.convertBackStringifiedValues(id, state); },