Beim Versuch, ein Excel-Dokument über Ajax abzurufen, treten asynchrone Probleme auf

8

Ich füge einem SharePoint JavaScript hinzu und versuche, eine Funktion zu schreiben, die ein Excel-Dokument oder vielmehr die darin enthaltenen Daten aus einer Bibliothek abruft. Ich habe bereits herausgefunden, wie das geht, aber die fraglichen Dateien sind zu groß, um zurückgegeben zu werden. Ich habe überlegt, die Größenbeschränkung für Ajax manuell festzulegen, aber ich habe keine Möglichkeit gefunden, dies zu tun. Daher besteht Plan B darin, für jede Zeile eine Abfrage zu senden

$("#button").click(function() {
			readFileRow(libraryUrl, "FileName.xlsx", "Sheet1", 1, "E", [])
			.done(function(cells) {
				console.log(xmlToJson(cells.documentElement));
			});
		});

/**
	 * Reads a file in SharePoint Library via ExcelRest and returns the document
	 *
	 * @params string libraryUrl
	 * @params string fileName
	 * @params string sheetName
	 * @params int rowNum
	 * @params string lastColumn
	 * @params string[][] finalResults
	 *
	 * @returns string[][]
	**/
	function readFileRow(libraryUrl, fileName, sheetName, rowNum, lastColumn, finalResults) {
		var fileUrl = libraryUrl + "/" + fileName + "/Model/Ranges('" + sheetName + "!A" + rowNum + "|" + lastColumn + rowNum + "')?$format=atom";

		return $.ajax({
			url: fileUrl,
			type: "GET",
			error: function (request, status, error) {
				console.log(error);
			},
		}).done(function(data) {
			jsonData = xmlToJson(data.documentElement);
			cells = serializeRange(jsonData);

			if(cells) {
				finalResults.push(cells);
				rowNum++;
				finalResults = readFileRow(libraryUrl, fileName, sheetName, rowNum, lastColumn, finalResults);
			}

			return $.when(finalResults);
		});
	}

Wie Sie sehen, versuche ich, das asynchrone Problem zu umgehen, indem ich die Funktion rekursiv aufrufe, wenn die Anforderung mit Daten zurückkommt, was bedeutet, dass sie weiter ausgeführt werden muss. Wenn ich eine console.log () kurz vor der Rückgabe platziere, kann ich sehen, dass die Ergebnisse so kompiliert werden, wie ich es brauche. Die Rückkehr vom Aufruf von readFileRow () erfolgt jedoch vor Abschluss des Prozesses und besteht aus der Antwort der allerersten Ajax-Abfrage, die anscheinend nicht über die Funktion .done () ausgeführt wurde. Ich habe versucht, die Rückgabe vor dem Ajax-Aufruf zu entfernen, dies führt jedoch nur zu einer Ausnahme, da die Rückgabe nicht mehr möglich ist und daher keine .done () -Funktion hat.

Kann jemand erkennen, was mit dieser Funktion nicht stimmt? Async-Funktionen sind nicht meine Stärke und ich bin ziemlich ratlos.

B. Allred
quelle

Antworten:

2

Es sieht so aus, als ob die Antwort einfach war, dass ich nicht vollständig verstanden habe, was verschiedene Methoden im Zusammenhang mit asynchronen Funktionen taten. Ich habe die Funktion folgendermaßen umstrukturiert und sie wie erwartet zum Laufen gebracht:

    $("#updateClusterDetails").click(function() {
        console.log("Update initiated");
        var baseFile = "AIF%20Test.xlsx";

        $.when(readFileRow(libraryUrl, baseFile, "Sheet1", 1, "E", new Array())).then(function(results) {
            console.log(results);
        });
    });

/**
 * Reads a file in SharePoint Library via ExcelRest and returns the document
 *
 * @params string libraryUrl
 * @params string fileLocation
 *
 * @returns Document/HTML
**/
function readFile(libraryUrl, fileLocation) {
    // The base url for the SharePoint document library
    var fileUrl = libraryUrl + fileLocation;

    return $.ajax({
        url: fileUrl,
        type: "GET",
        error: function (request, status, error) {
            console.log(error);
        },
        success: function(data) {
            return $.when(data);
        }
    });
}

    /**
 * Reads a series of rows in an Excel file in SharePoint Library via ExcelRest and returns the row data
 *
 * @params string libraryUrl
 * @params string fileName
 * @params string sheetName
 * @params int rowNum
 * @params string lastColumn
 * @params string[][] currentResults
 *
 * @returns string[][]
**/
function readFileRows(libraryUrl, fileName, sheetName, rowNum, lastColumn, currentResults) {
    var fileUrl = "/" + fileName + "/Model/Ranges('" + sheetName + "!A" + rowNum + "|" + lastColumn + rowNum + "')?$format=atom";

    return readFile(libraryUrl, fileUrl)
    .then(function(data) {
        jsonData = xmlToJson(data.documentElement);
        cells = serializeRange(jsonData);

        if(!cells) {
            return $.when(currentResults);
        }
        else {
            currentResults.push(cells);
            return $.when(readFileRow(libraryUrl, fileName, sheetName, rowNum + 1, lastColumn, currentResults));
        }

    });
}
B. Allred
quelle
0

Ich kann Ihre genaue Implementierung nicht testen, aber hier ist, wie ich es zuvor gemacht habe:

readFileRowVerwenden Sie für den Ajax-Aufruf .thenanstelle von, .doneda dies ein Versprechen für den Rückgabewert der .thenFunktion anstelle des Ajax-Objekts selbst zurückgibt.

Dann können Sie einfach finalResultsohne das Wann und die rekursiven und anfänglichen Aufrufe zurückkehren, readFileRowdie für awaitdiese Rückgabe erforderlich sind .

Ich bin auch nicht besonders versiert in Versprechungen und asynchroner Codierung, aber so habe ich vorher ähnliche Dinge gemacht.

$("#button").click(function() {
	let cells = await readFileRow(libraryUrl, "FileName.xlsx", "Sheet1", 1, "E", [])
	console.log(xmlToJson(cells.documentElement));
});

/**
	 * Reads a file in SharePoint Library via ExcelRest and returns the document
	 *
	 * @params string libraryUrl
	 * @params string fileName
	 * @params string sheetName
	 * @params int rowNum
	 * @params string lastColumn
	 * @params string[][] finalResults
	 *
	 * @returns string[][]
	**/
	function readFileRow(libraryUrl, fileName, sheetName, rowNum, lastColumn, finalResults) {
		var fileUrl = libraryUrl + "/" + fileName + "/Model/Ranges('" + sheetName + "!A" + rowNum + "|" + lastColumn + rowNum + "')?$format=atom";

		return $.ajax({
			url: fileUrl,
			type: "GET",
			error: function (request, status, error) {
				console.log(error);
			},
		}).then(function(data) {
			jsonData = xmlToJson(data.documentElement);
			cells = serializeRange(jsonData);

			if(cells) {
				finalResults.push(cells);
				rowNum++;
				finalResults = await readFileRow(libraryUrl, fileName, sheetName, rowNum, lastColumn, finalResults);
			}

			return finalResults;
		});
	}

Tugzrida
quelle
0

Anstatt die Anrufe gleichzeitig zu tätigen (warten Sie, bis Sie zur Rückgabe aufgefordert werden, und rufen Sie erst dann zum nächsten auf), können Sie sie parallel mit anrufen Promise.all.

Während der folgende Code Ihren Code überhaupt nicht verwendet (weil ich ihn nicht zum Laufen bringen kann), zeigt er, wie er sich verhalten sollte. Wenn es Ihren Fall nicht zu 100% widerspiegelt, lassen Sie es mich wissen.

Die Logik lautet:

  1. Wenn wir die Gesamtzahl der Zeilen abrufen, damit wir wissen, wie viele Anforderungen wir erstellen sollen, müssen wir auf diese Anforderung warten, da wir ihre Daten für den Rest der Anforderungen benötigen.
  2. Erstellen Sie ein Array mit allen Versprechungen und geben Sie es an weiter Promise.all. Das thengibt alle Daten zusammen zurück.

Lassen Sie mich wissen, wenn das Beispiel nicht klar ist.

const data = new Array(10).fill().map((_, i) => ({
  foo: `bar${i}`
}));

/* simulate the ajax call to get the total number of rows
 TODO replace it with the actual call */
function getRowsCount() {
  return Promise.resolve(data.length);
}

/* simulate the ajax call to get row's data by index
 TODO replace it with the actual call*/
function getRow(index) {
  return Promise.resolve(data[index]);
}

function getData() {
  return getRowsCount()
    .then(rowCount => {
      const allRequests = new Array(rowCount).fill().map((_, index) => getRow(index));
      return Promise.all(allRequests)
    });
}

getData().then(data => {
  console.log(data);
});

Mosh Feu
quelle
Das hat mir nicht wirklich geholfen. Ich denke nicht, dass Sie unbedingt falsch liegen, aber ich konnte nicht die Lektion bekommen, die Sie unterrichtet haben, um sie auf meinen Code anzuwenden.
B. Allred
Meinetwegen. Obwohl es
Mosh Feu