De kracht van JavaScript in FileMaker

Door Jan Zelenka.

Hoi, mijn naam is Jan Zelenka, en ik wil u laten zien hoe een efficiënte implementatie van een JavaScript-functiebibliotheek in FileMaker kan worden bereikt.

Op sommige gebieden is de JavaScript-engine aanzienlijk sneller dan FileMaker. U kunt ernstige prestatiewinst boeken als u JavaScript-functies gebruikt in plaats van FileMaker aangepaste functies of scripts.

Hier is een voorbeeld. Het is in feite dezelfde business case die ik gebruik om de technieken genoemd in dit artikel te demonstreren (download link hieronder). Stel dat je een grote set meetresultaten ontvangt in JSON. Je app moet deze resultaten verwerken en wat aggregatie uitvoeren, bijvoorbeeld het gemiddelde berekenen van de ontvangen resultaten.

Ik wist dat FileMaker’s omgang met JSON behoorlijk traag was. Toch vond ik de resultaten verbazingwekkend. De opdracht is om een gemiddelde te berekenen van 10.000 waarden die zijn opgeslagen in een voorbeeld JSON array. Hier is hoe lang het duurde voor mijn machine om de berekening uit te voeren:

  • FileMaker custom function: 180 seconden
  • JavaScript: 100 ms

Zoals u kunt zien, kan een naadloze integratie van JavaScript in een FileMaker-toepassing een cruciaal onderdeel van uw project zijn. Ik zal enkele gedachten delen over hoe u een set JavaScript-functies in uw FileMaker-app kunt opslaan en hoe u deze functies kunt oproepen vanuit elk script in uw project – en dat met slechts één scriptstap Perform Script.
Zie het als een vervanging voor de FileMaker aangepaste functies die alleen voor uw scripts beschikbaar zijn.

Om meteen alle verwarring te vermijden: dit artikel gaat niet over HTML. Het gaat niet over hoe FileMaker visueel kan worden verbeterd met behulp van webpagina’s die zijn verrijkt met JavaScript. Dit gaat over zuivere JavaScript-functiebibliotheken die het mogelijk maken voordeel te halen uit de prestaties van de JavaScript-engine die die van de FileMaker-calculation engine overtreffen.

Achtergrondinformatie

Sinds FileMaker versie 19 is een nieuwe scriptstap toegevoegd: Perform JavaScript in Web Viewer. Deze scriptstap neemt de Web Viewer die is gespecificeerd door zijn objectnaam en roept de gevraagde JavaScript-functie aan. Dat werkt allemaal heel goed voor specifieke gebruikssituaties, maar zodra u begint te denken aan het opbouwen van een herbruikbare JavaScript-functiebibliotheek, realiseert u zich dat het niet zo eenvoudig is om deze bibliotheek van overal in uw bestand te benaderen. Laten we eerst eens kijken naar een aantal minder efficiënte methodes die ik zou willen vermijden.

JavaScript functie bibliotheek – methoden om te vermijden.

Verborgen Webviewer op elke lay-out

Aangezien elk FileMaker script in een context van een layout wordt uitgevoerd, zou u ervoor kunnen kiezen om op elke layout van uw bestand een Web Viewer object buiten de opmaakgrens te plaatsen. Vanuit het oogpunt van toekomstig onderhoud is dit de minst gunstige methode. Als u van plan bent uw JavaScript in een tabel op te slaan, zou elke layout een relatie met die tabel vereisen. En zelfs als je een aangepaste functie kiest om de JavaScript code te bewaren, dan heb je nog steeds dezelfde webviewer nodig op elke layout, wat tegen een van de basisregels van software ontwikkeling ingaat: herhaal jezelf niet.

Verborgen venster

U maakt een speciale layout voor de Web Viewer en telkens wanneer u uw bibliotheek moet oproepen, opent u een nieuw venster buiten de schermgrenzen, bijvoorbeeld op -5000; -5000. Dit is al beter; je hoeft maar één layout en één Web Viewer te onderhouden. Helaas betekent het openen en sluiten van een nieuw venster een aanzienlijke prestatie-achteruitgang, dus ik zou het ook niet aanraden.

De oplossing

Laten we dan eens kijken wat er kan worden gedaan om de bovengenoemde tekortkomingen te omzeilen.

Apart bestand

Ik zou voorstellen om zo’n bibliotheek in een apart bestand te plaatsen. Je hoeft maar één versie te onderhouden, en het kan toegankelijk worden gemaakt voor meerdere projecten. Laten we het js-worker noemen. Je voegt js-worker toe aan je hoofdbestand als een Externe Gegevensbron voordat je het voor de eerste keer gebruikt (meestal in de OnFirstWindow trigger handler), open je het

Open File [ Open hidden: On ; "js-worker" ]

Open Hidden: On is het interessante deel hier. Het zorgt ervoor dat er geen extra venster wordt geopend en dat de Web Viewer die onze JavaScript bibliotheek host, zal werken in het FileMaker virtuele venster (met een beetje overtuigingskracht – ik kom daar later op terug) dat is gemaakt voor het js-worker bestand.

Als bijlage bij deze blog vindt u 2 bestanden:

  • js-worker.fmp12: een vereenvoudigde implementatie van het JS bibliotheek bestand.
  • master.fmp12: een voorbeeldbestand dat wordt gebruikt om het laden van de bibliotheek en het gebruik ervan te demonstreren.
  • experiment.json: een gegevensbestand met een JSON-geformatteerde matrix van hypothetische metingen met het resultaat van elke meting in milliseconden.

Laten we eens kijken naar de interessante delen van de js-worker.fmp12 implementatie.
Het bestand is geconfigureerd om automatisch te openen met een Alleen-lezen toegang account. Om volledige toegang te krijgen, gebruik het menu Scripts > Utilities > Relogin. Het account is Admin, Het wachtwoord is admin.

The Concept

Het js-worker bestand voorziet in een entry point script. Wanneer het wordt aangeroepen, roept het op zijn beurt de gevraagde JS functie aan en wacht tot een globale variabele aangeeft dat de JS klaar is en een resultaat beschikbaar is. Dit wordt bereikt doordat de JS-functie een ander FM-script aanroept en het resultaat als parameter aan dit script doorgeeft. Dit script stelt dan de benodigde globale variabelen in en sluit af, waarna het entry point script ze kan oppakken en het resultaat terug kan sturen naar de oorspronkelijke aanroeper.

Library tabel

Deze tabel bevat JS bibliotheken die u beschikbaar zou willen hebben. Elk record vertegenwoordigt een bibliotheek, geïdentificeerd door een unieke naam (veld Name), en met de volledige JS code van uw bibliotheek (veld Code). Optioneel kunt u een bibliotheek als standaard aanwijzen. Als er een standaardbibliotheek bestaat, wordt deze gebruikt wanneer een oproep wordt gedaan zonder de bibliotheeknaam op te geven.

JSW.Call script

Dit is het script waarmee de bibliotheek wordt aangeroepen. Het accepteert een parameter in de vorm van een JSON string en maakt het mogelijk om de bibliotheek te specificeren om te gebruiken (optioneel), de functie om aan te roepen, en een parameter om aan de functie door te geven (optioneel). Na het navigeren naar de werklayout en het lokaliseren van de bibliotheek, voert dit script de aanroep van de JS-functie uit:

Set Variable [ $$finished ; Value: "" ]
Refresh Window [ ]
Perform JavaScript in Web Viewer [ Object Name: "js-worker" ; Function Name: $function ; Parameters: $parameters ]

Ten eerste, laten we niet vergeten dat dit allemaal gebeurt in een FileMaker virtueel venster. Ik vermoed dat dat de reden is waarom de Refresh Window stap nodig is. Zonder deze stap werkt de oproep naar de JS functie niet.
Door de asynchrone aard van JavaScript, kan de laatste script stap ook niet de return waarde van de JS functie teruggeven. Daarom moeten we de globale variabele $$finished resetten, zodat die kan worden gebruikt om het resultaat op te halen zodra de JS klaar is:

Loop
    Exit Loop If [ $$finished ]
End Loop
Exit Script [ Text Result: $$response ]
Demo Library

Het JS Worker bestand bevat een bibliotheek genaamd Demo met een functie genaamd averageTime. Deze functie neemt een JSON matrix van meetobjecten en berekent de gemiddelde tijd van alle metingen in de matrix. Hier is een 3-item voorbeeld van de array:

{
    "measurements": [
        {
            "time": 5.3499795065668
        },
        {
            "time": 5.48264791500604
        },
        {
            "time": 5.05030523259211
        }
    ]
}

Hier is de JavaScript functie zelf:

function averageTime ( experiment ) {
    if ( typeof experiment === 'string' )
        experiment = JSON.parse( experiment );
    var totalTime = 0;
    for ( const measurement of experiment.measurements ) {
        totalTime += measurement.time;
    }
    const averageTime = totalTime / experiment.measurements.length;
    FileMaker.PerformScriptWithOption(
            'Internal.ReceiveResult'
            , averageTime
            , '5'
            );
}

De FileMaker.PerformScriptWithOption methode is de enige directe manier om gegevens van de JS functie door te geven aan de FM script engine. De 2e parameter moet worden ingesteld op het resultaat dat we willen verkrijgen uit de JS functie-aanroep. De derde parameter moet 5 zijn om het JSW.Call script te laten pauzeren terwijl Internal.ReceiveResult de globale variabelen instelt en het daarna weer te laten hervatten.

Internal.ReceiveResult script

Aangezien de JS functie het JSW.Call script op pauze zet, wordt deze uitgevoerd, zet de globale variabelen $$response en $$finished, en sluit af:

Set Variable [ $$response ; Value: JSONSetElement( "{}"; [ "result"; "data"; JSONString ]; [ "data"; Get( ScriptParameter ); JSONRaw ] ) ]
Set Variable [ $$finished ; Value: True ]
Exit Script [ Text Result: "" ]

Zodra dat gebeurt, hervat het JSW.Call script, pikt de $$respons waarde op, en geeft die door aan de oorspronkelijke aanroeper.

Met dit bestand kun je de js-worker testen en wat vergelijkingen maken tussen JS en FM prestaties. Het opent met de wachtwoordloze Admin account auto-logged in en presenteert een eenvoudige layout met 2 knoppen: JavaScript en FileMaker. Ze laden beide de inhoud van het bestand experiment.json, berekenen de gemiddelde tijd van alle metingen en presenteren het resultaat in een aangepast dialoogvenster. Bovendien meten ze de tijd die nodig is om dit gemiddelde te berekenen. Het is duidelijk dat de eerste knop gebruik maakt van de hierboven toegelichte JavaScript techniek, en de andere van een while loop omwikkeld door een aangepaste functie.

Conclusie

Kortom, we hebben een efficiënte techniek verkend die de JavaScript kracht van slechts één Perform Script call van alle scripts in uw bestanden toont. Bovendien hebben we aangetoond dat in tijdkritische operaties, JavaScript absoluut de voorkeur zou moeten hebben
Ik hoop dat je dit artikel nuttig vond en ik wens je veel JavaScript-plezier!