Leistungsoptimierung mit der Excel-JavaScript-API
Es gibt mehrere Möglichkeiten, allgemeine Aufgaben mit der Excel-JavaScript-API auszuführen. Sie werden erhebliche Leistungsunterschiede zwischen verschiedenen Ansätzen feststellen. Dieser Artikel enthält Anleitungen und Codebeispiele, die Ihnen zeigen, wie Sie allgemeine Aufgaben mithilfe der Excel-JavaScript-API effizient ausführen.
Wichtig
Viele Leistungsprobleme können durch die empfohlene Verwendung von load
- und sync
-Aufrufen behoben werden. Informationen zum effizienten Arbeiten mit anwendungsspezifischen APIs finden Sie im Abschnitt "Leistungsverbesserungen mit den anwendungsspezifischen APIs" unter Ressourcenlimits und Leistungsoptimierung für Office-Add-Ins .
Vorübergehendes Anhalten von Excel-Prozessen
Excel verfügt über eine Reihe von Hintergrundaufgaben, die auf Eingaben sowohl von Benutzern als auch von Ihrem Add-In reagieren. Einige dieser Excel-Prozesse können so gesteuert werden, dass ein Leistungsvorteil erzielt wird. Dies ist besonders hilfreich, wenn Ihre Add-Ins mit großen Datenmengen arbeiten.
Berechnung vorübergehend unterbrechen
Wenn Sie versuchen, eine Operation mit einer gro?en Anzahl von Zellen durchzuf?hren (z.B. den Wert eines gro?en Bereichsobjekts setzen) und es Ihnen nichts ausmacht, die Berechnung in Excel vor?bergehend anzuhalten, w?hrend Ihre Operation beendet ist, empfehlen wir Ihnen, die Berechnung bis zum n?chsten Aufruf von context.sync()
anzuhalten.
In der Referenzdokumentation zum Anwendungsobjekt finden Sie Informationen zur Verwendung der suspendApiCalculationUntilNextSync()
-API zum Anhalten und erneuten Aktivieren von Berechnungen auf sehr praktische Weise. Der folgende Code veranschaulicht das vorübergehende Anhalten der Berechnung.
await Excel.run(async (context) => {
let app = context.workbook.application;
let sheet = context.workbook.worksheets.getItem("sheet1");
let rangeToSet: Excel.Range;
let rangeToGet: Excel.Range;
app.load("calculationMode");
await context.sync();
// Calculation mode should be "Automatic" by default
console.log(app.calculationMode);
rangeToSet = sheet.getRange("A1:C1");
rangeToSet.values = [[1, 2, "=SUM(A1:B1)"]];
rangeToGet = sheet.getRange("A1:C1");
rangeToGet.load("values");
await context.sync();
// Range value should be [1, 2, 3] now
console.log(rangeToGet.values);
// Suspending recalculation
app.suspendApiCalculationUntilNextSync();
rangeToSet = sheet.getRange("A1:B1");
rangeToSet.values = [[10, 20]];
rangeToGet = sheet.getRange("A1:C1");
rangeToGet.load("values");
app.load("calculationMode");
await context.sync();
// Range value should be [10, 20, 3] when we load the property, because calculation is suspended at that point
console.log(rangeToGet.values);
// Calculation mode should still be "Automatic" even with suspend recalculation
console.log(app.calculationMode);
rangeToGet.load("values");
await context.sync();
// Range value should be [10, 20, 30] when we load the property, because calculation is resumed after last sync
console.log(rangeToGet.values);
});
Beachten Sie, dass nur Formelberechnungen angehalten werden. Alle geänderten Verweise werden weiterhin neu erstellt. Wenn Sie beispielsweise ein Arbeitsblatt umbenennen, werden alle Verweise in Formeln auf dieses Arbeitsblatt immer noch aktualisiert.
Anhalten der Bildschirmaktualisierung
Excel zeigt Änderungen, die das Add-In vornimmt, in etwa so an, wie sie im Code vorgenommen werden. Für große, iterative Datensätze müssen Sie diesen Fortschritt vielleicht nicht in Echtzeit auf dem Bildschirm anzeigen. Application.suspendScreenUpdatingUntilNextSync()
hält visuelle Aktualisierungen für Excel an, bis das Add-In context.sync()
aufruft oder bis Excel.run
endet (wodurch context.sync
implizit aufgerufen wird). Beachten Sie, dass in Excel bis zur nächsten Synchronisation keine Zeichen von Aktivität angezeigt werden. Das Add-In sollte Benutzern entweder Hilfestellung geben, um sie auf diese Verzögerung vorzubereiten, oder eine Statusleiste zum Anzeigen von Aktivität bereitstellen.
Hinweis
Rufen suspendScreenUpdatingUntilNextSync
Sie nicht wiederholt auf (z. B. in einer Schleife). Wiederholte Aufrufe führen dazu, dass das Excel-Fenster flackert.
Aktivieren und Deaktivieren von Ereignissen
Die Leistung eines Add-Ins kann durch Deaktivieren von Ereignissen verbessert werden. Ein Codebeispiel, in dem gezeigt wird, wie Ereignisse aktiviert und deaktiviert werden, finden Sie im Artikel Arbeiten mit Ereignissen.
Daten in Tabellen importieren
Wenn Sie versuchen, eine große Datenmenge direkt in ein Table-Objekt zu importieren (z. B. mithilfe von TableRowCollection.add()
), kann die Leistung langsam sein. Wenn Sie versuchen, eine neue Tabelle hinzuzufügen, sollten Sie zuerst die Daten eingeben, indem Sie festlegen range.values
und dann aufrufen worksheet.tables.add()
, um eine Tabelle über dem Bereich zu erstellen. Wenn Sie versuchen, Daten in eine vorhandene Tabelle zu schreiben, schreiben Sie die Daten über table.getDataBodyRange()
in ein Bereichsobjekt, und die Tabelle wird automatisch erweitert.
Nachfolgend sehen Sie ein Beispiel dieses Ansatzes:
await Excel.run(async (context) => {
let sheet = context.workbook.worksheets.getItem("Sheet1");
// Write the data into the range first.
let range = sheet.getRange("A1:B3");
range.values = [["Key", "Value"], ["A", 1], ["B", 2]];
// Create the table over the range
let table = sheet.tables.add('A1:B3', true);
table.name = "Example";
await context.sync();
// Insert a new row to the table
table.getDataBodyRange().getRowsBelow(1).values = [["C", 3]];
// Change a existing row value
table.getDataBodyRange().getRow(1).values = [["D", 4]];
await context.sync();
});
Hinweis
Sie k?nnen ein Tabellenobjekt bequem in ein Bereichsobjekt konvertieren, indem Sie die Methode Table.convertToRange() verwenden.
Bewährte Methoden für die Begrenzung der Nutzlastgröße
Die Excel-JavaScript-API hat Größenbeschränkungen für API-Aufrufe. Excel im Web hat eine Nutzlastgrößenbeschränkung für Anforderungen und Antworten von 5 MB, und eine API gibt einen RichAPI.Error
Fehler zurück, wenn dieser Grenzwert überschritten wird. Auf allen Plattformen ist ein Bereich für Get-Vorgänge auf fünf Millionen Zellen beschränkt. Große Bereiche überschreiten in der Regel beide Einschränkungen.
Die Nutzlastgröße einer Anforderung ist eine Kombination der folgenden drei Komponenten.
- Die Anzahl der API-Aufrufe
- Die Anzahl der Objekte, z
Range
. B. Objekte - Die Länge des festzulegenden oder abzurufenden Werts
Wenn eine API den RequestPayloadSizeLimitExceeded
Fehler zurückgibt, verwenden Sie die in diesem Artikel dokumentierten Bewährten Methoden, um Ihr Skript zu optimieren und den Fehler zu vermeiden.
Strategie 1: Verschieben unveränderter Werte aus Schleifen
Begrenzen Sie die Anzahl der Prozesse, die innerhalb von Schleifen auftreten, um die Leistung zu verbessern. Im folgenden Codebeispiel context.workbook.worksheets.getActiveWorksheet()
kann aus der for
Schleife verschoben werden, da es sich innerhalb dieser Schleife nicht ändert.
// DO NOT USE THIS CODE SAMPLE. This sample shows a poor performance strategy.
async function run() {
await Excel.run(async (context) => {
let ranges = [];
// This sample retrieves the worksheet every time the loop runs, which is bad for performance.
for (let i = 0; i < 7500; i++) {
let rangeByIndex = context.workbook.worksheets.getActiveWorksheet().getRangeByIndexes(i, 1, 1, 1);
}
await context.sync();
});
}
Das folgende Codebeispiel zeigt Logik, die dem vorherigen Codebeispiel ähnelt, aber mit einer verbesserten Leistungsstrategie. Der Wert context.workbook.worksheets.getActiveWorksheet()
wird vor der for
Schleife abgerufen, da dieser Wert nicht bei jeder Ausführung der for
Schleife abgerufen werden muss. Nur Werte, die sich im Kontext einer Schleife ändern, sollten innerhalb dieser Schleife abgerufen werden.
// This code sample shows a good performance strategy.
async function run() {
await Excel.run(async (context) => {
let ranges = [];
// Retrieve the worksheet outside the loop.
let worksheet = context.workbook.worksheets.getActiveWorksheet();
// Only process the necessary values inside the loop.
for (let i = 0; i < 7500; i++) {
let rangeByIndex = worksheet.getRangeByIndexes(i, 1, 1, 1);
}
await context.sync();
});
}
Strategie 2: Erstellen weniger Bereichsobjekte
Erstellen Sie weniger Bereichsobjekte, um die Leistung zu verbessern und die Nutzlastgröße zu minimieren. Zwei Ansätze zum Erstellen von weniger Bereichsobjekten werden in den folgenden Artikelabschnitten und Codebeispielen beschrieben.
Aufteilen jedes Bereichsarrays in mehrere Arrays
Eine Möglichkeit, weniger Bereichsobjekte zu erstellen, besteht darin, jedes Bereichsarray in mehrere Arrays aufzuteilen und dann jedes neue Array mit einer Schleife und einem neuen context.sync()
Aufruf zu verarbeiten.
Wichtig
Verwenden Sie diese Strategie nur, wenn Sie zuerst festgestellt haben, dass Sie die Größenbeschränkung für Nutzlastanforderungen überschreiten. Die Verwendung mehrerer Schleifen kann die Größe jeder Nutzlastanforderung verringern, um eine Überschreitung des Grenzwerts von 5 MB zu vermeiden. Die Verwendung mehrerer Schleifen und mehrerer context.sync()
Aufrufe wirkt sich jedoch auch negativ auf die Leistung aus.
Im folgenden Codebeispiel wird versucht, ein großes Array von Bereichen in einer einzelnen Schleife und dann in einem einzelnen context.sync()
Aufruf zu verarbeiten. Die Verarbeitung von zu vielen Bereichswerten in einem context.sync()
Aufruf führt dazu, dass die Nutzlastanforderungsgröße den Grenzwert von 5 MB überschreitet.
// This code sample does not show a recommended strategy.
// Calling 10,000 rows would likely exceed the 5MB payload size limit in a real-world situation.
async function run() {
await Excel.run(async (context) => {
let worksheet = context.workbook.worksheets.getActiveWorksheet();
// This sample attempts to process too many ranges at once.
for (let row = 1; row < 10000; row++) {
let range = sheet.getRangeByIndexes(row, 1, 1, 1);
range.values = [["1"]];
}
await context.sync();
});
}
Das folgende Codebeispiel zeigt eine Logik, die dem vorherigen Codebeispiel ähnelt, jedoch mit einer Strategie, die eine Überschreitung des Grenzwerts für die Anforderung von 5 MB Nutzlast vermeidet. Im folgenden Codebeispiel werden die Bereiche in zwei separaten Schleifen verarbeitet, und auf jede Schleife folgt ein context.sync()
Aufruf.
// This code sample shows a strategy for reducing payload request size.
// However, using multiple loops and `context.sync()` calls negatively impacts performance.
// Only use this strategy if you've determined that you're exceeding the payload request limit.
async function run() {
await Excel.run(async (context) => {
let worksheet = context.workbook.worksheets.getActiveWorksheet();
// Split the ranges into two loops, rows 1-5000 and then 5001-10000.
for (let row = 1; row < 5000; row++) {
let range = worksheet.getRangeByIndexes(row, 1, 1, 1);
range.values = [["1"]];
}
// Sync after each loop.
await context.sync();
for (let row = 5001; row < 10000; row++) {
let range = worksheet.getRangeByIndexes(row, 1, 1, 1);
range.values = [["1"]];
}
await context.sync();
});
}
Festlegen von Bereichswerten in einem Array
Eine weitere Möglichkeit, weniger Bereichsobjekte zu erstellen, besteht darin, ein Array zu erstellen, eine Schleife zum Festlegen aller Daten in diesem Array zu verwenden und dann die Arraywerte an einen Bereich zu übergeben. Dies profitiert sowohl von der Leistung als auch von der Nutzlastgröße. Anstatt für jeden Bereich in einer Schleife aufzurufen range.values
, range.values
wird einmal außerhalb der Schleife aufgerufen.
Im folgenden Codebeispiel wird gezeigt, wie Sie ein Array erstellen, die Werte dieses Arrays in einer for
Schleife festlegen und dann die Arraywerte an einen Bereich außerhalb der Schleife übergeben.
// This code sample shows a good performance strategy.
async function run() {
await Excel.run(async (context) => {
const worksheet = context.workbook.worksheets.getActiveWorksheet();
// Create an array.
const array = new Array(10000);
// Set the values of the array inside the loop.
for (let i = 0; i < 10000; i++) {
array[i] = [1];
}
// Pass the array values to a range outside the loop.
let range = worksheet.getRange("A1:A10000");
range.values = array;
await context.sync();
});
}
Siehe auch
Office Add-ins