Verwenden des Abfrage-Generator-Musters

Verwenden des Abfrage-Generator-Musters in Hilo (Windows Store-Apps mit JavaScript und HTML)

[ Dieser Artikel richtet sich an Windows 8.x- und Windows Phone 8.x-Entwickler, die Windows-Runtime-Apps schreiben. Wenn Sie für Windows 10 entwickeln, finden Sie weitere Informationen unter neueste Dokumentation]

Aus: Umfassende Entwicklung einer Windows Store-App mit JavaScript: Hilo

Leitfaden-Logo

Vorherige Seite | Nächste Seite

Hilo implementiert eine Kombination aus dem Generator-Muster und dem Abfrageobjektmuster, um Abfrageobjekte für den Zugriff auf Daten im Windows-Dateisystem zu erstellen.

Download

Herunterladen des Hilo-Beispiels
Buch herunterladen (PDF)

Anweisungen zum heruntergeladenen Code finden Sie unter Erste Schritte mit Hilo.

Sie erfahren Folgendes:

  • So wird's gemacht: Implementieren des Generator-Musters für eine mit JavaScript erstellte Windows Store-App
  • So wird's gemacht: Implementieren des Abfrageobjektmusters für eine mit JavaScript erstellte Windows Store-App
  • So wird's gemacht: Abrufen von Eigenschaften im Voraus zum Optimieren der Leistung
  • So wird's gemacht: Erstellen und Ausführen einer Dateisystemabfrage

Betrifft

  • Windows-Runtime für Windows 8
  • Windows-Bibliothek für JavaScript
  • JavaScript

Generator-Muster

Das Generator-Muster ist ein Objekterstellungsmuster, bei dem Sie Eingaben vornehmen, um in mehreren Schritten ein komplexes Objekt zu erstellen. Die Darstellung des Objekts kann sich je nach Dateneingabe unterscheiden. In Hilo erstellen wir ein Abfrage-Generator-Objekt, dessen einzige Funktion in der Erstellung eines Abfrageobjekts besteht, das eine Abfrage kapselt. Alle Seiten in Hilo benötigen Zugriff auf den lokalen Bildordner, um Bilder anzuzeigen. Daher sind die Einstellungen des Abfrage-Generators speziell auf eine Windows-Dateisystemabfrage ausgerichtet.

Hilo\Hilo\month\month.js


this.queryBuilder = new Hilo.ImageQueryBuilder();


Beim Erstellen des Abfrage-Generators legen wir die Generator-Optionen eines Dateisystems im Konstruktor fest. Nach dem Erstellen eines Abfrage-Generators können Sie dessen jeweiligen Member zum Festlegen von Optionen aufrufen, die speziell für die Seite und die Abfrage gelten. Der folgende Code gibt an, dass das Abfrage-Generator-Objekt ein Abfrageobjekt erstellt, für das Folgendes zutrifft:

  • Es kann an die Benutzeroberfläche gebunden werden.
  • Es enthält einen Vorabrufaufruf für eine Dateieigenschaft.
  • Es ist auf sechs Elemente in den Abfrageergebnissen beschränkt.

Hilo\Hilo\hub\hubPresenter.js


this.queryBuilder
    .bindable(true)
    .prefetchOptions(["System.ItemDate"])
    .count(maxImageCount);


Die verketteten Funktionen im obigen Code veranschaulichen den flüssigen Codierungsstil, der unterstützt wird, da das in Hilo verwendete Generator-Muster die Fluent-Benutzeroberfläche implementiert. Die Fluent-Benutzeroberfläche ermöglicht einen flüssigen Codierungsstil, was zum Teil auf die Implementierung sorgfältig benannter Methoden zurückzuführen ist. Im Abfrage-Generator-Objekt gibt jede Funktion in der Kette sich selbst (das Abfrage-Generator-Objekt) zurück. Dies ermöglicht den flüssigen Codierungsstil. Informationen zur Fluent-Benutzeroberfläche finden Sie unter Fluent-Benutzeroberfläche.

Nach dem Festlegen der gewünschten Optionen im Abfrage-Generator erstellen wir mithilfe der Einstellungen ein Windows.Storage.Search.QueryOptions-Objekt. Anschließend erstellen wir die Abfrage, indem wir das Abfrageoptionenobjekt als Argument an createFileQueryWithOptions übergeben. Zum Ausführen der Abfrage rufen wir dann getFilesAsync auf. Ein Beispiel für das Erstellen und Ausführen einer Abfrage finden Sie unter Exemplarische Vorgehensweise für den Code.

Allgemeine Informationen zum Generator-Muster finden Sie unter Generator-Muster.

[Oben]

Abfrageobjektmuster

Im Abfrageobjektmuster definieren Sie mithilfe einer Reihe von Eigenschaften eine Abfrage und führen die Abfrage dann aus. Sie können Optionen im Abfrage-Generator ändern und den Generator dann verwenden, um ein neues Abfrageobjekt zu erstellen. Der folgende Code zeigt die Konstruktorfunktion für das intern definierte Abfrageobjekt. Die übergebenen Einstellungen dienen zum Erstellen einer Dateiabfrage (_buildQueryOptions und _buildFileQuery).

Hilo\Hilo\imageQueryBuilder.js


function QueryObjectConstructor(settings) {
    // Duplicate and the settings by copying them
    // from the original, to a new object. This is
    // a shallow copy only.
    //
    // This prevents the original queryBuilder object
    // from modifying the settings that have been
    // sent to this query object.
    var dupSettings = {};
    Object.keys(settings).forEach(function (key) {
        dupSettings[key] = settings[key];
    });

    this.settings = dupSettings;

    // Build the query options.
    var queryOptions = this._buildQueryOptions(this.settings);
    this._queryOptionsString = queryOptions.saveToString();

    if (!this.settings.folder.createFileQueryWithOptions) {
        var folder = supportedFolders[this.settings.folderKey];
        if (!folder) {
            // This is primarily to help any developer who has to extend Hilo.
            // If they add support for a new folder, but forget to register it
            // at the head of this module then this error should help them
            // identify the problem quickly.
            throw new Error("Attempted to deserialize a query for an unknown folder: " + settings.folderKey);
        }
        this.settings.folder = folder;
    }

    this.fileQuery = this._buildFileQuery(queryOptions);
},


Das Abfrageobjektmuster erleichtert auch das Serialisieren und Deserialisieren der Abfrage. Hierzu verwenden werden Methoden für das Abfrageobjekt (üblicherweise mit entsprechenden Namen) verwendet. Allgemeine Informationen zum Abfrageobjektmuster finden Sie unter Abfrageobjekt.

Bei der Entwicklung von Hilo haben wir die anfängliche Implementierung des Repositorymusters durch das Abfrageobjektmuster ersetzt. Der Hauptunterschied zwischen dem Repositorymuster und dem Abfrageobjektmuster besteht darin, dass Sie beim Repositorymuster eine Abstraktion Ihrer Datenquelle erstellen und Methoden wie getImagesByType aufrufen. Beim Abfrageobjektmuster legen Sie dagegen Eigenschaften im Abfrage-Generator fest und erstellen basierend auf dem aktuellen Zustand des Generators dann einfach eine Abfrage.

Der Wechsel zum Abfrageobjektmuster erfolgte hauptsächlich aus zwei Gründen. Zum einen haben wir festgestellt, dass wir auf verschiedenen Seiten unterschiedliche Abfrageobjekte erstellen, die größtenteils den gleichen Code und die gleichen Werte verwenden. Zum anderen fügen wir Repositoryfunktionen hinzu, die nicht mehr generisch waren. Der folgende Code enthält ein Beispiel für eine spezielle Repositoryfunktion, die wir aus Hilo entfernt haben.


   getQueryForMonthAndYear: function(monthAndYear){   
       var options = this.getQueryOptions();   
       options.applicationSearchFilter = 'taken: ' + monthAndYear;   
       return options.saveToString();   
   },


Wir sind zu der Ansicht gelangt, dass das Hinzufügen von seitenspezifischen Funktionen zum Repository den Code zu unflexibel macht. Daher haben wir beschlossen, die Implementierung mithilfe eines Abfrage-Generators reibungsloser zu gestalten.

[Oben]

Exemplarische Vorgehensweise für den Code

Der Code definiert die Abfrage-Generator-Klasse in imageQueryBuilder.js. Außerdem macht der Code das Abfrage-Generator-Objekt (Hilo.ImageQueryBuilder) verfügbar, sodass es mithilfe von WinJS.Namespace.define in der App verwendet werden kann.

Hilo\Hilo\imageQueryBuilder.js


WinJS.Namespace.define("Hilo", {
    ImageQueryBuilder: ImageQueryBuilder
});


In Hilo kann eine bestimmte Seite einen Abfrage-Generator anfordern, indem zuerst ein neues ImageQueryBuilder-Objekt erstellt wird. Üblicherweise erstellen wir den Abfrage-Generator in der ready-Funktion der einzelnen Seiten.

Hilo\Hilo\month\month.js


this.queryBuilder = new Hilo.ImageQueryBuilder();


Nach Erstellung des Abfrage-Generators übergeben wir ihn dem Presenter der Seite. Weitere Informationen zum Model-View-Presenter-Muster, mit dem wir unterschiedliche Ansichten erstellt haben, finden Sie unter Verwenden eines eigenen Darstellungsmusters.

Hilo\Hilo\month\month.js


this.presenter = new Hilo.month.MonthPresenter(loadingIndicator, this.semanticZoom, this.zoomInListView, zoomOutListView, hiloAppBar, this.queryBuilder);


Wenn Sie das Abfrage-Generator-Objekt erstellen, ruft der Konstruktor für den Abfrage-Generator reset auf, um die Standardwerte festzulegen.

Hilo\Hilo\imageQueryBuilder.js


function ImageQueryBuilderConstructor() {
    this.reset();
},


In der reset-Funktion des Abfrage-Generator-Objekts legen wir alle Standardwerte (wie Quelldateiordner und unterstützte Dateitypen) fest.

Hilo\Hilo\imageQueryBuilder.js


reset: function () {
    this._settings = {};
    this._set("fileTypes", [".jpg", ".jpeg", ".tiff", ".png", ".bmp", ".gif"]);
    this._set("prefetchOption", fileProperties.PropertyPrefetchOptions.imageProperties);

    this._set("thumbnailOptions", fileProperties.ThumbnailOptions.useCurrentScale);
    this._set("thumbnailMode", fileProperties.ThumbnailMode.picturesView);
    this._set("thumbnailSize", 256);

    this._set("sortOrder", commonFileQuery.orderByDate);
    this._set("indexerOption", search.IndexerOption.useIndexerWhenAvailable);
    this._set("startingIndex", 0);
    this._set("bindable", false);

    return this;
},


Die Werte werden dem Array in der _set-Methode hinzugefügt.

Hilo\Hilo\imageQueryBuilder.js


_set: function (key, value) {
    this._settings[key] = value;
}


Nach dem Erstellen eines Abfrage-Generators können Sie für den Generator zusätzliche Optionen festlegen, die für die gewünschte Abfrage gelten sollen. So legen wir im folgenden Code beispielsweise Optionen auf der Hubseite fest. Diese Optionen geben an, dass der Generator gebunden werden kann, und legen eine Vorabrufoption für das Elementdatum (System.ItemDate) sowie die Anzahl auf 6 fest. Der Anzahlwert gibt an, dass auf der Hubseite insgesamt nur sechs Bilder angezeigt werden.

Hilo\Hilo\hub\hubPresenter.js


this.queryBuilder
    .bindable(true)
    .prefetchOptions(["System.ItemDate"])
    .count(maxImageCount);


Beim Aufrufen von bindable fügen wir dem Array der Abfrage-Generator-Einstellungen einfach eine neue bindable-Eigenschaft hinzu. Diese Eigenschaft verwenden wir später zum Erstellen bindbarer Objekte, die die zurückgegebenen Dateisystemobjekte umschließen. Weitere Informationen finden Sie unter Erzielen der Feststellbarkeit für Dateisystemobjekte.

Hilo\Hilo\imageQueryBuilder.js


bindable: function (bindable) {
    // `!!` is a JavaScript coersion trick to convert any value
    // in to a true boolean value. 
    //
    // When checking equality and boolean values, JavaScript 
    // coerces `undefined`, `null`, `0`, `""`, and `false` into 
    // a boolean value of `false`. All other values are coerced 
    // into a boolean value of `true`.
    //
    // The first ! then, negates the coerced value. For example,
    // a value of "" (empty string) will be coerced in to `false`.
    // Therefore `!""` will return `true`. 
    //
    // The second ! then inverts the negated value to the
    // correct boolean form, as a true boolean value. For example,
    // `!!""` returns `false` and `!!"something"` returns true.
    this._set("bindable", !!bindable);
    return this;
},


Wenn Sie Dateivorgänge mit der Windows-Runtime ausführen, kann es hilfreich sein, die Windows-Runtime anzuweisen, das Abrufen bestimmter Dateieigenschaften zu optimieren. Legen Sie dazu die Vorabrufoption für eine Abfrage fest. Hier verwenden wir den übergebenen System.ItemDate-Parameter und legen die prefetchOption-Eigenschaft des Abfrage-Generators auf den gleichen Wert fest. Zuerst werden für den Abfrage-Generator, wie hier dargestellt, die Eigenschaften für das Vorab-Abrufen festgelegt. Dieser Wert wird später beim Erstellen der Abfrage verwendet.

Hilo\Hilo\imageQueryBuilder.js


prefetchOptions: function (attributeArray) {
    this._set("prefetchOption", fileProperties.PropertyPrefetchOptions.none);
    this._set("prefetchAttributes", attributeArray);
    return this;
},


Nach dem Festlegen der Optionen des Abfrage-Generators rufen wir build auf, um die eigentliche Abfrage zu erstellen. Wir übergeben ein Windows.Storage.KnownFolders-Objekt, um den festgelegten Dateisystemordner anzugeben.

Hilo\Hilo\hub\hubPresenter.js


var query = this.queryBuilder.build(this.folder);


Die build-Methode erstellt ein neues, intern definiertes Abfrageobjekt. In der Konstruktorfunktion des Abfrageobjekts (QueryObjectConstructor) fügen wir die Einstellungen des Abfrage-Generators an.

Hilo\Hilo\imageQueryBuilder.js


function QueryObjectConstructor(settings) {
    // Duplicate and the settings by copying them
    // from the original, to a new object. This is
    // a shallow copy only.
    //
    // This prevents the original queryBuilder object
    // from modifying the settings that have been
    // sent to this query object.
    var dupSettings = {};
    Object.keys(settings).forEach(function (key) {
        dupSettings[key] = settings[key];
    });

    this.settings = dupSettings;

    // Build the query options.
    var queryOptions = this._buildQueryOptions(this.settings);
    this._queryOptionsString = queryOptions.saveToString();

    if (!this.settings.folder.createFileQueryWithOptions) {
        var folder = supportedFolders[this.settings.folderKey];
        if (!folder) {
            // This is primarily to help any developer who has to extend Hilo.
            // If they add support for a new folder, but forget to register it
            // at the head of this module then this error should help them
            // identify the problem quickly.
            throw new Error("Attempted to deserialize a query for an unknown folder: " + settings.folderKey);
        }
        this.settings.folder = folder;
    }

    this.fileQuery = this._buildFileQuery(queryOptions);
},


Vom Konstruktor aus ruft das Abfrageobjekt _buildQueryOptions auf. Diese Funktion wandelt die Abfrage-Generator-Einstellungen in ein gültiges Windows.Storage.Search.QueryOptions-Objekt um. An dieser Stelle optimieren wir die Leistung durch Festlegen von Vorabrufoptionen. Für die Hubseite wird die ItemDate-Eigenschaft als zweiter Parameter in setPropertyPrefetch übergeben.

Hilo\Hilo\hub\hub.js


_buildQueryOptions: function (settings) {
    var queryOptions = new search.QueryOptions(settings.sortOrder, settings.fileTypes);
    queryOptions.indexerOption = settings.indexerOption;

    queryOptions.setPropertyPrefetch(settings.prefetchOption, settings.prefetchAttributes);

    if (this.settings.monthAndYear) {
        queryOptions.applicationSearchFilter = translateToAQSFilter(settings.monthAndYear);
    }

    return queryOptions;
},


Das vorab abgerufene Elementdatum wird nicht direkt in der Hubansicht verwendet. Datumswerte spielen in der Hubansicht keine Rolle, weshalb einfach die ersten sechs Bilder angezeigt werden. Aber in hub.js verwenden wird das Elementdatum, um vor der Übergabe an andere Seiten (beispielsweise die Detailseite) den korrekten Indexwert für ein Bild festzulegen. Die Windows-Runtime behandelt das Abrufen des Elementdatums bedarfsabhängig in einem separaten asynchronen Vorgang. Dieser Vorgang ist relativ langsam und wird immer nur für eine einzelne Datei ausgeführt. Wenn wir die Elementdatumswerte vorab (also vor den eigentlichen Bildern) abrufen, können wir die Leistung optimieren.

Für die Monatsseite legen wir auch eine Vorabrufoption für die Miniaturansichten (setThumbnailPrefetch) fest. Weitere Informationen zum Vorabrufen von Miniaturansichten finden Sie unter Verbessern der Leistung.

Beim Erstellen eigener Apps empfiehlt es sich, die Optionen für das Vorabrufen durch Interagieren mit dem Dateisystem zu testen, um zu ermitteln, ob Sie die Leistung verbessern können.

Nach dem Aufrufen von _buildQueryOptions ruft der Abfrage-Objektkonstruktor _buildFileQuery auf. Diese Funktion wandelt das QueryOptions-Objekt mithilfe von Windows.Storage.StorageFolder.createFileQueryWithOptions in eine Windows-Runtime-Dateiabfrage um.

Hilo\Hilo\imageQueryBuilder.js


_buildFileQuery: function (queryOptions) {
    return this.settings.folder.createFileQueryWithOptions(queryOptions);
},


Anschließend wird die Abfrage ausgeführt. Auf der Hubseite sieht der Code zum Ausführen der Abfrage wie folgt aus.

Hilo\Hilo\hub\hubPresenter.js


return query.execute()
    .then(function (items) {
        if (items.length === 0) {
            self.displayLibraryEmpty();
        } else {
            self.bindImages(items);
            self.animateEnterPage();
        }
    });


Beim Aufrufen der Ausführung wird getFilesAsync zum tatsächlichen Abrufen der Bilder verwendet. Anschließend wird geprüft, ob die bindable-Eigenschaft in der Abfrage festgelegt war. Wenn "bindable" festgelegt ist, bedeutet dies, dass zurückgegebene StorageFile-Objekte umschlossen werden müssen, damit sie für die Bindung an die UI geeignet sind. Informationen zum Umschließen des Dateisystemobjekts für die Bindung an die UI finden Sie unter Erzielen der Feststellbarkeit für Dateisystemobjekte.

Hilo\Hilo\imageQueryBuilder.js


execute: function () {
    var start, count;
    var queryPromise;

    switch (arguments.length) {
        case (0):
            start = this.settings.startingIndex;
            count = this.settings.count;
            break;
        case (1):
            start = arguments[0];
            count = 1;
            break;
        case (2):
            start = arguments[0];
            count = arguments[1];
            break;
        default:
            throw new Error("Unsupported number of arguments passed to `query.execute`.");
    }

    if (count) {
        // Limit the query to a set number of files to be returned, which accounts
        // for both the `count(n)` and `imageAt(n)` settings from the query builder.
        queryPromise = this.fileQuery.getFilesAsync(start, count);
    } else {
        queryPromise = this.fileQuery.getFilesAsync();
    }

    if (this.settings.bindable) {
        // Create `Hilo.Picture` objects instead of returning `StorageFile` objects
        queryPromise = queryPromise.then(this._createViewModels);
    }

    return queryPromise;
},


Wenn das Abfrageergebnis in der abgeschlossenen Zusage zurückgegeben wird, rufen wir bindImages auf. Die Hauptaufgabe dieser Funktion ist die Zuordnung des nicht gruppierten Indexwerts für jedes zurückgegebene Bild zu einem monatsbasierten Gruppenindexwert. Anschließend wird mithilfe von setDataSource die Bindung an die Benutzeroberfläche angefordert.

Hilo\Hilo\hub\hubPresenter.js


bindImages: function (items) {
    this.dataSource = items;

    if (items.length > 0) {
        items[0].className = items[0].className + " first";
    }

    // We need to know the index of the image with respect to
    // to the group (month/year) so that we can select it
    // when we navigate to the detail page.
    var lastGroup = "";
    var indexInGroup = 0;
    items.forEach(function (item) {
        var group = item.itemDate.getMonth() + " " + item.itemDate.getFullYear();
        if (group !== lastGroup) {
            lastGroup = group;
            indexInGroup = 0;
        }

        item.groupIndex = indexInGroup;
        indexInGroup++;
    });

    this.listview.setDataSource(items);
},


Die Hubseite verwendet für ihre Datenquelle ein Binding.List-Element aus WinJS. Informationen zu den in Hilo verwendeten Datenquellen finden Sie unter Verwenden von Datenquellen.

[Oben]

Erzielen der Feststellbarkeit für Dateisystemobjekte

Aus dem Dateisystem zurückgegebene Objekte liegen nicht in einem Format vor, das die Bindung (Feststellbarkeit) für Steuerelemente wie ListView und FlipView zulässt. Der Grund: Die Windows-Runtime ist nicht änderbar. Es gibt ein WinJS-Hilfsprogramm, mit dem Objekte zu Observable-Objekten gemacht werden können, dieses Hilfsprogramm versucht jedoch, das Objekt zu ändern, indem es das Objekt mit einem Proxy umschließt. Wenn zurückgegebene StorageFile-Objekte an die UI gebunden werden müssen, werden sie im Abfrage-Generator als "bindable" (bindbar) festgelegt. Für bindbare Objekte ruft die execute -Funktion im Abfrageobjekt _createViewModels auf. Dadurch werden Hilo.Picture-Objekten die Dateisystemobjekte zugeordnet.

Hilo\Hilo\imageQueryBuilder.js


_createViewModels: function (files) {
    return WinJS.Promise.as(files.map(Hilo.Picture.from));
}


Der Code, der hier zu sehen ist, zeigt die Konstruktorfunktion für ein Picture-Objekt. In dieser Funktion werden dem Objekt Zeichenfolgenwerte als Eigenschaften hinzugefügt. Nach dem Festlegen der Eigenschaften können diese zum Binden an die UI verwendet werden. Beispielsweise wird die url-Eigenschaft durch Aufrufen des URL-Caches der App (nicht dargestellt) festgelegt. Der Cache ruft URL.createObjectURL auf. createObjectURL verwendet als Eingabe ein Blob mit binären Daten (übergebene Miniaturansicht) und gibt eine Zeichenfolgen-URL zurück.

Hilo\Hilo\Picture.js


function PictureConstructor(file) {
    var self = this;

    this.addUrl = this.addUrl.bind(this);

    this.storageFile = file;
    this.urlList = {};
    this.isDisposed = false;

    this._initObservable();
    this.addProperty("name", file.name);
    this.addProperty("isCorrupt", false);
    this.addProperty("url", "");
    this.addProperty("src", "");
    this.addProperty("itemDate", "");
    this.addProperty("className", "thumbnail");

    this.loadFileProperties();
    this.loadUrls();
},


Tipp  Vor der Navigation zu einer neuen Seite müssen Sie Objekte, die Sie unter Verwendung von URL.createObjectURL erstellt haben, freigeben. Damit vermeiden Sie einen möglichen Arbeitsspeicherverlust. Verwenden Sie hierzu URL.revokeObjectURL. Dies wird in Hilo in urlCache.js (nicht dargestellt) aufgerufen. Informationen zum Aufspüren von Arbeitsspeicherverlusten sowie andere Leistungstipps finden Sie unter Verbessern der Leistung sowie unter Analysieren von Daten zur Speicherauslastung.
 

[Oben]

 

 

Anzeigen:
© 2017 Microsoft