ajaxを介してExcelドキュメントを取得しようとすると、非同期の問題が発生する


8

JavaScriptをSharePointに追加し、ライブラリからExcelドキュメントまたはその中のデータを取得する関数を記述しようとしています。その方法はすでにわかりましたが、問題のファイルが大きすぎて返せません。ajaxのサイズ制限を手動で設定することを検討しましたが、これを行う方法が見つからなかったため、プランBは各行にクエリを送信します

$("#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);
		});
	}

ご覧のとおり、リクエストでデータが返されたときに関数を再帰的に呼び出すことで非同期の問題を回避しようとしています。つまり、実行を継続する必要があります。戻る直前にconsole.log()を配置すると、結果が必要に応じてコンパイルされていることがわかります。ただし、readFileRow()の呼び出しからの戻りは、プロセスが完了する前に返され、最初のajaxクエリからの応答で構成され、明らかに.done()関数を介して実行されていません。ajax呼び出しの前にある戻り値を削除しようとしましたが、戻り値はもはや処理できず、したがって.done()関数がないため、例外が発生するだけです。

誰もがこの機能の何が悪いのかを見つけることができますか?非同期関数は私の強みではなく、私はかなり困惑しています。

回答:


2

答えは単純に、非同期関数に関連するさまざまなメソッドが何をしているかを完全に理解していなかったようです。次のように関数を再構成し、期待どおりに機能するようにしました。

    $("#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));
        }

    });
}

0

私はあなたの正確な実装をテストすることはできませんが、これは私が以前にそれを行った方法です:

のajax呼び出しではreadFileRow.then代わりに.doneを使用します。これは.then、ajaxオブジェクト自体ではなく、関数の戻り値のプロミスを返すためです。

次にfinalResults、いつ、およびこの戻りreadFileRowが必要な再帰的および最初の呼び出しなしで戻ることができますawait

私はプロミスと非同期コーディングにも精通していませんが、これは以前に同様のことをした方法です。

$("#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;
		});
	}


0

呼び出しを並行して行うのではなく(戻る要求を待ってから、次の呼び出しを呼び出すまで)、を使用して並行して呼び出すことができますPromise.all

以下のコードはコードをまったく使用していませんが(実際に機能させることができないため)、コードがどのように動作するかを示しています。ケースが100%反映されていない場合は、お知らせください。

ロジックは次のとおりです。

  1. 作成する必要があるリクエストの量を把握できるように、行の総数を取得します。残りのリクエストにはデータが必要なので、このリクエストを待つ必要があります。
  2. すべてのpromiseで配列を作成し、それをに渡しPromise.allます。then結合されたすべてのデータを返します。

例が明確でない場合はお知らせください。

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);
});


これはあまり役に立ちませんでした。私はあなたが必ずしも間違っているとは思いませんが、私のコードに適用するためにあなたが教えているどんなレッスンも得ることができませんでした。
B. Allred

けっこうだ。それはパフォーマンスの点で重要なものですが..
Mosh Feu
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.