DESITE md 2.8 vs 3.0 | Formular Migrationshinweis

In DESITE BIM ab Version 3.0 wird durch ein Update der zugrundeliegenden Web-Technologie eine Reihe an Anpassungen notwendig. 

Diese Anpassungen betreffen alle selbst erstellten Webformulare und Details Widgets. Alle Skripte, z.B. Objekt-Skripte, bleiben von der Änderung unberührt.

 

Asynchrone API-Calls 

Die Hauptänderung innerhalb der Webformulare ist, dass alle API-Calls nun nicht mehr synchron, sondern asynchron abgehandelt werden. In JavaScript wird dafür eine Funktion mit dem Keyword „async“ versehen. Eine asynchrone Funktion wird parallel zur aufrufenden Funktion ausgeführt, somit kann nicht mehr garantiert werden, dass Operationen in Aufrufreihenfolge begonnen und abgeschlossen werden. Daher widmet sich der nachfolgende Abschnitt dem Umgang mit asynchronen Funktionen und ihren Rückgabewerten.

1. Abschlusszeitpunkt ist nicht relevant:

Der einfachste Fall ist, dass der Abschlusszeitpunkt der aufzurufenden Funktion keine Relevanz hat. In diesem Fall kann der asynchrone Aufruf wie bisher ausgeführt werden. Es ist jedoch zu beachten, dass z.B. ein Aufruf von „getVisibleElements“ nach einem asynchronen Aufruf von „showAll“ noch nicht auf eine aktuelle Liste sichtbarer Elemente zurückgreifen kann. 

function run()
{
  desiteAPI.showAll(true, 'geometry');
  desiteAPI.showAll(true, 'documents');
}

2. Warten auf einzelne/mehrere Promises:

Wenn der Anwender auf die Fertigstellung einer asynchronen Funktion, synchron reagieren möchte, dann bietet JavaScript die Möglichkeit mit Promise-Objekten zu arbeiten. Bei einem asynchronen Funktionsaufruf wird ein Promise, anstelle des eigentlichen Rückgabewerts, zurückgeben. Dieses Promise repräsentiert eine noch nicht abgeschlossene Operation. Es kann nun mit Hilfe des await-Operators auf den Abschuss der Operation gewartet werden. Der Rückgabewert des await-Operators ist nun der eigentlich Rückgabewert der Funktion. Jedoch ist die Nutzung des await-Operators selbst nur in einer asynchronen Funktion möglich, da der Fortlauf des Programms sonst nicht mehr gewährleistet werden könnte. Die wartende Funktion muss daher auch mit den „async“ Keyword versehen werden. 

async function waitForOnePromise()
{
  ids = await desiteAPI.getVisibleElements();
  for(var i = 0; i < ids.length; i++)
  {
      var obj = await desiteAPI.getAsJSON(ids[i]);    
      /* or explicit */
      var promise = desiteAPI.getAsJSON(ids[i]);
      var obj = await promise;
  }
}

Neben der Möglichkeit auf einzelne Promises zu warten, kann auch auf mehrere Promises gleichzeitig gewartet werden. Dies hat den Vorteil, dass der Funktionsablauf weniger lange angehalten werden muss und sich somit die Gesamtlaufzeit des Aufrufs verkürzt. Es werden alle Promises in einem Array gesammelt und dann zeitgleich der await-Operator auf alle Promises aufgerufen, der Rückgabewert ist ein Array der Funktionsrückgabewerte. 

async function waitForAllPromises()
{
  ids = await desiteAPI.getVisibleElements();
  var promises = [];
  for(var i = 0; i < ids.length; i++)
  {
      promises.push(desiteAPI.getAsJSON(ids[i]));
  }
  var objs = await Promise.all(promises);
}

3. Callbacks:

Eine weitere Möglichkeit auf asynchronen Funktionsaufrufe zu reagieren, ist die Mitgabe einer Callback-Funktion. Diese Funktion wird als weiterer Parameter in den asynchronen Funktionsaufruf übergeben und nach Funktionsabschluss aufgerufen. Die Callback-Funktion übergibt als Parameter den Rückgabewert des eigentlichen Funktionsaufrufs. Die aufrufende Funktion kann bei der Nutzung eines Callbacks parallel weiterarbeiten und muss demnach auch nicht mit dem „async“ Keyword versehen werden. 

function runWithCallback()
{
  desiteAPI.getVisibleElements(function(ids)
  {
      for(var i = 0; i < ids.length; i++)
      {
          desiteAPI.getAsJSON(ids[i], function(obj)
          {
              /* do something with object */
          });
      }
  });
}

Zusammenfassend lässt sich sagen, es ist immer vorteilhaft NICHT auf einzelne API-Calls warten zu müssen und asynchron mit Callbacks zu reagieren. Alternativ sollte möglichst auf viele Operationen parallel gewartet und diese dann gemeinsam abgearbeitet werden. 

Als Referenz findet sich ein Skript mit Performance Tests zum Download bereit (Benchmark.zip). Hier werden noch einmal die unterschiedlichen Optionen und ihre Ausführungszeiten verglichen. Ein Test mit 100 erzeugten Objekten zeigt, dass die einzelnen Aufrufe ungefähr doppelt so lange brauchen wie die gesammelten Aufrufe und Callbacks. Diese Beobachtungen lassen sich aber nicht verallgemeinern, sondern stellen nur einen Richtwert dar. 

blobid0.png

 

Einstiegspunkt 

Bisher wurde als Einstiegspunkt zur Initialisierung von Daten auf das „load“ Event des HTML Bodys reagiert. Dies ist nun nicht mehr möglich, da das neue API zu diesem Zeitpunkt noch nicht initialisiert ist. Es wird jetzt nach erfolgreicher Initialisierung ein eigenes Event „desiteload“ gesendet, auf dieses Event kann mit einem registrierten Event Listener reagiert werden. 

addEventListener('desiteload', function(event)
{
  /* do your initialization here */
});

 

API-Funktionen mit internem Zustand

Größere Vorsicht als bislang ist geboten, wenn API-Funktionen verwendet werden, die einen internen Zustand haben.
Beispielsweise, wenn mittels openFile() eine Datei geöffnet, dann mit writeToFile() evtl. mehrfach geschrieben und mit closeFile() wieder geschlossen wird. Da die Aufrufe in genau dieser Reihenfolge erfolgen müssen, muss der WebForm-Entwickler sicherstellen, dass diese nicht asynchron und somit out-of-order ausgeführt werden.

Ein weiteres typisches und wichtiges Beispiel sind die Iterator-Funktionen, wo beispielsweise mit itByFilter() eine Objektmenge definiert und dann mit itHasNext() und itNext() darüber iteriert wird. Diese Gruppe von Funktionen ist deswegen als deprecated gekennzeichnet. Verwenden Sie stattdessen filterByProperty(), welches die gefilterte Objekt-Liste nicht DESITE-intern verwaltet. Die Liste wird als Parameter übergeben und als Return-Wert zurückgeliefert.

Näheres entnehmen Sie bitte der API-Dokumentation.



War dieser Beitrag hilfreich?
0 von 0 fanden dies hilfreich

Benötigen Sie weitere Unterstützung? Kontaktieren Sie unser Support Team