NEWS
Verarbeiten von Promises - mit Fetch und API Adapter
-
Hallo,
ich versuche die ganze Zeit nachfolgendes Problem zu lösen:
- Zusammenfassung im nächsten Post -
Ich möchte über den API Adapter Werte per Java in meine Website schreiben.
Nchfolgendes Skript holt mir die Daten als JSON. Innerhalb des fetch und der .then Funktionen kann ich per myJson.val an den Wert. Sobald ich raus bin, gibt die Funktion mir ein Promises zurück.Wie kann ich nur die Value zurück bekommen oder aus dem Promise auslesen?
Ziel ist es in diesem Beispiel mit einer IF Abfrage den Button verschieden einzufärben.Skript:
function get_api_value(id) { var myJson = fetch('http://IP:Port/get/' + id + '?prettyPrint') .then(function(response) { return response.json(); }) .then(function(myJson) { return myJson; }); console.log(myJson.Object) }
Antwort:
Promise { <state>: "pending" } <state>: "fulfilled" <value>: Object { val: 5.42, ack: true, ts: 1625742939234, … } _id: "alias.0.Klimaanlage.Power_aktuell.ACTUAL" ack: true acl: Object { object: 1636, owner: "system.user.admin", ownerGroup: "system.group.administrator", … } common: Object { name: "Power_aktuell", role: "value.power", type: "number", … } from: "system.adapter.admin.0" lc: 1640209597885 native: Object { } q: 0 ts: 1625742939234 type: "state" user: "system.user.admin" val: 5.4 <prototype>: Object { … } __defineGetter__: function __defineGetter__() __defineSetter__: function __defineSetter__() __lookupGetter__: function __lookupGetter__() __lookupSetter__: function __lookupSetter__() __proto__: constructor: function Object() hasOwnProperty: function hasOwnProperty() isPrototypeOf: function isPrototypeOf() propertyIsEnumerable: function propertyIsEnumerable() toLocaleString: function toLocaleString() toString: function toString() valueOf: function valueOf() <get __proto__()>: function __proto__() <set __proto__()>: function __proto__()
-
Hier ein vereinfachtes Beispiel:
var out = fetch('http://IP/get/alias.0.Klimaanlage.Power_aktuell.ACTUAL?prettyPrint') .then(function(myJson) { return "1"; }); console.log(out);
output:
Promise { <state>: "pending" } <state>: "fulfilled" <value>: "1"
Wie kann ich value = 1 aus dem Promise in eine Variable schreiben?
-
@smarty-ml was liefert?
var out = await fetch('http://192.168.31.3:8087/get/alias.0.Klimaanlage.Power_aktuell.ACTUAL?prettyPrint'; log(out);
-
@fastfoot
Die direkte Antwort:{ "val": 21.97, "ack": true, "ts": 1625742939234, "q": 0, "from": "system.adapter.admin.0", "user": "system.user.admin", "lc": 1640217238396, "common": { "name": "Power_aktuell", "role": "value.power", "type": "number", "unit": "W", "read": true, "write": true, "alias": { "id": "shelly.0.SHSW-PM#F4CFA2E502F5#1.Relay0.Power" }, "custom": { "sql.0": { "enabled": true, "changesOnly": false, "debounce": "1000", "retention": "2678400", "changesRelogInterval": "600", "changesMinDelta": 1, "storageType": "", "aliasId": "", "counter": false } } }, "native": {}, "acl": { "object": 1636, "owner": "system.user", "ownerGroup": "system.group", "state": 1636 }, "_id": "alias.0.Klimaanlage.Power_aktuell.ACTUAL", "type": "state" }
Im Log:
Response { type: "cors", url: "http://IP/get/alias.0.Klimaanlage.Power_aktuell.ACTUAL?prettyPrint", redirected: false, status: 200, ok: true, statusText: "OK", headers: Headers, body: ReadableStream, bodyUsed: false } (...)
-
@smarty-ml und jetzt das out parsen und dann kannst du easy zugreifen auf was du willst:
let o=JSON.parse(out); let val =o.val; log(val);
-
@fastfoot leider nein:
Uncaught (in promise) SyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data
Nachfolgendes mit dem Response aus dem Browser funktioniert:
i = JSON.parse('{ "val": 21.86, "ack": true, "ts": 1625742939234, "q": 0, "from": "system.adapter.admin.0", "user": "system.user.admin", "lc": 1640242659631, "common": { "name": "Power_aktuell", "role": "value.power", "type": "number", "unit": "W", "read": true, "write": true, "alias": { "id": "shelly.0.SHSW-PM#F4CFA2E502F5#1.Relay0.Power" }, "custom": { "sql.0": { "enabled": true, "changesOnly": false, "debounce": "1000", "retention": "2678400", "changesRelogInterval": "600", "changesMinDelta": 1, "storageType": "", "aliasId": "", "counter": false } } }, "native": {}, "acl": { "object": 1636, "owner": "system.user.admin", "ownerGroup": "system.group.administrator", "state": 1636 }, "_id": "alias.0.Klimaanlage.Power_aktuell.ACTUAL", "type": "state" }'); console.log(i.val);
-
@smarty-ml Poste doch mal bitte exakt das was im Log steht wenn du die beiden Zeilen von @fastfoot ausführen lässt.
Dein Post zeigt 2 Code-Schnipsel, beide sind nicht so wie sie im Log dargestellt sind - daher fehlen Informationen.
A.
-
var out = await fetch('http://192.168.31.3:8087/get/alias.0.Klimaanlage.Power_aktuell.ACTUAL?prettyPrint'); let o=JSON.parse(out); let val =o.val; log(val); Uncaught (in promise) SyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data <anonymous> debugger eval code:7 async* debugger eval code:10
-
@smarty-ml Ich meinte die Ausgaben von diesem Code:
@fastfoot sagte in Verarbeiten von Promises - mit Fetch und API Adapter:
@smarty-ml was liefert?
var out = await fetch('http://192.168.31.3:8087/get/alias.0.Klimaanlage.Power_aktuell.ACTUAL?prettyPrint'; log(out);
-
Nächste Versuch
10:23:19.227 var out = await fetch('http://192.168.31.3:8087/get/alias.0.Klimaanlage.Power_aktuell.ACTUAL?prettyPrint'); console.log(out); 10:23:19.256 Response { type: "cors", url: "http://192.168.31.3:8087/get/alias.0.Klimaanlage.Power_aktuell.ACTUAL?prettyPrint", redirected: false, status: 200, ok: true, statusText: "OK", headers: Headers, body: ReadableStream, bodyUsed: false } body: ReadableStream { locked: false } locked: false <prototype>: ReadableStream.prototype { cancel: cancel(), getReader: getReader(), tee: tee(), … } bodyUsed: false headers: Headers { } <prototype>: HeadersPrototype { append: append(), delete: delete(), get: get(), … } ok: true redirected: false status: 200 statusText: "OK" type: "cors" url: "http://192.168.31.3:8087/get/alias.0.Klimaanlage.Power_aktuell.ACTUAL?prettyPrint" <prototype>: ResponsePrototype { clone: clone(), arrayBuffer: arrayBuffer(), blob: blob(), … } arrayBuffer: function arrayBuffer() blob: function blob() body: bodyUsed: clone: function clone() constructor: function () formData: function formData() headers: json: function json() ok: redirected: status: statusText: text: function text() type: url: Symbol(Symbol.toStringTag): "Response" <get body()>: function body() <get bodyUsed()>: function bodyUsed() <get headers()>: function headers() <get ok()>: function ok() <get redirected()>: function redirected() <get status()>: function status() <get statusText()>: function statusText() <get type()>: function type() <get url()>: function url() <prototype>: Object { … }
-
async function getjson(url = '', data = {}) { const response = await fetch(url, { }); return response.json(); } async function get_api_value(ip,id) { let o; await getjson('http://' + ip + '/get/' + id + '?prettyPrint') .then(data => { o = data; }); return o.val; }
Meine Lösung: Ich deklariere eine weitere Variable, welche ich im .then(...) mit den Daten Fülle und gebe diese im return aus. Im Unterschied zu vorher muss ich nicht mit dem Promise weiter arbeiten. Innerhalb von .then(...) kann ich nämlich auf das Response als Object/JSON zugreifen, so wie oben beschrieben.
Ich glaube ich habe damit eine Lösung, aber schlaut mich bitte mal auf.
-
@smarty-ml sagte in Verarbeiten von Promises - mit Fetch und API Adapter:
Ich glaube ich habe damit eine Lösung, aber schlaut mich bitte mal auf.
await und .then zusammen macht in 99,99% der Fälle keinen Sinn.
let o; await getjson(...).then(data => { o = data; });
ist äquivalent zu
let o = await getjson(...);
Und um deine beiden Funktionen in eins zu packen, reicht das:
async function get_api_value(ip,id) { // 1. HTTP request machen const response = await fetch('http://' + ip + '/get/' + id + '?prettyPrint'); // 2. Antwort umwandeln return response.json().val; }
-
OKAY, danke ich habe es!
Der Fehler lag also in meinen Gedankengängen beim .then und await.
Ich schlaue mich da mal auf ^^Zum Verständnis:
Await und .then erzwingen eine Pause, bis die entsprechende Funktion beendet ist. Lasse ich in der finalen Funktion das await weg, so führt er beide Befehle zum gleichen Zeitpunkt durch und findet daher kein Objekt "response"?
Richtig?
-
@smarty-ml Eine async-Funktion gibt implizit einen Promise (ein Wert, der erst später "fertig" ist) zurück. Wenn du diesen nicht mit
await
abwartest, geht's wie du schon erkannt hast sofort weiter, ohne dass das Ergebnis schon da ist.await
nutzt übrigens unter der Haube auch.then
, macht den Ablauf des Codes aber klarer. -
@smarty-ml sagte in Verarbeiten von Promises - mit Fetch und API Adapter:
var out = await fetch('http://192.168.31.3:8087/get/alias.0.Klimaanlage.Power_aktuell.ACTUAL?prettyPrint'); let o=JSON.parse(out); let val =o.val; log(val); Uncaught (in promise) SyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data <anonymous> debugger eval code:7 async* debugger eval code:10
dein out ist bereits ein Objekt. Lasse Zeile 2 Weg und in Zeile 3
let val=out.val
-
Nabend!
Das Thema ist etwas älter, aber vielleicht antwortet ja trotzdem jemand....
Ich möchte eine einfache fetch api Anfrage durchführen. Leider bekomme ich eine Fehlermeldung.
Hat jemand ne Idee?Hier mein Code:
import fetch from 'node-fetch'; async function getWetter() { const data = await fetch("https://api.weather.gov/gridpoints/OKX/35,35/forecast"); const ergebnis = data.json(); console.log(ergebnis); } getWetter();
Hier die Fehlermeldung:
18:57:36.521 info javascript.0 (202) Start javascript script.js.Javascript.ioBroker.Test.fetch 18:57:36.541 error javascript.0 (202) script.js.Javascript.ioBroker.Test.fetch compile failed: at script.js.Javascript.ioBroker.Test.fetch:1 18:57:45.066 info javascript.0 (202) Stop script script.js.Javascript.ioBroker.Test.fetch
Hier die Ausgabe von npm ls node-fetch:
root@iobroker:/opt/iobroker# npm ls node-fetch iobroker.inst@3.0.0 /opt/iobroker ├─┬ iobroker.backitup@2.6.16 │ └─┬ google-auth-library@8.7.0 │ └─┬ gaxios@5.0.2 │ └── node-fetch@2.6.9 ├─┬ iobroker.iot@1.14.2 │ └─┬ canvas@2.11.0 │ └─┬ @mapbox/node-pre-gyp@1.0.10 │ └── node-fetch@2.6.9 deduped └─┬ iobroker.javascript@6.1.4 └── node-fetch@3.3.1 root@iobroker:/opt/iobroker#
Schönen Abend und Grüße!!!
Karel
-
Keiner ne Idee???
-
@karel-puhli ,
ich denke das du das Modul fetch hier hinzufügen musst, ist aber ohne Gewähr.
-
Hi Walter!
Danke für Deine Antwort!
Ist in beiden Zeilen drin!