Cố gắng lấy tài liệu Excel thông qua ajax, gặp sự cố không đồng bộ


8

Tôi đang thêm JavaScript vào SharePoint và tôi đang cố gắng viết một hàm lấy tài liệu Excel, hay đúng hơn là dữ liệu trong đó, từ thư viện. Tôi đã tìm ra cách để làm điều đó, nhưng các tệp trong câu hỏi quá lớn để được trả lại. Tôi đã xem xét việc đặt giới hạn kích thước cho ajax theo cách thủ công, nhưng tôi chưa tìm thấy cách nào để thực hiện việc này, vì vậy Kế hoạch B là gửi truy vấn cho mỗi hàng

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

Như bạn có thể thấy, tôi đang cố gắng khắc phục sự cố không đồng bộ bằng cách gọi hàm đệ quy khi yêu cầu quay lại với dữ liệu, nghĩa là nó phải tiếp tục chạy. Khi tôi đặt console.log () ngay trước khi trả về, tôi có thể thấy rằng nó đang biên dịch kết quả khi tôi cần. Tuy nhiên, trả về từ việc gọi readFileRow () sẽ quay trở lại trước khi quá trình kết thúc và bao gồm phản hồi từ truy vấn ajax đầu tiên, dường như không được chạy qua hàm .done (). Tôi đã thử xóa trả lại trước lệnh gọi ajax, nhưng điều này chỉ gây ra ngoại lệ, vì trả lại không còn có thể sau đó và do đó không có hàm .done ().

Bất cứ ai cũng có thể phát hiện ra những gì sai với chức năng này? Các chức năng không đồng bộ không phải là sở trường của tôi và tôi khá bối rối.

Câu trả lời:


2

Có vẻ như câu trả lời chỉ đơn giản là tôi đã không hiểu đầy đủ các phương pháp khác nhau liên quan đến các chức năng không đồng bộ đang làm gì. Tôi đã cấu trúc lại chức năng theo cách sau và khiến nó hoạt động như mong đợi:

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

Tôi không thể kiểm tra việc triển khai chính xác của bạn, nhưng đây là cách tôi đã thực hiện trước đây:

Đối với lệnh gọi ajax readFileRow, hãy sử dụng .thenthay vì vì .doneđiều này sẽ trả về một lời hứa cho giá trị trả về của .thenhàm thay vì chính đối tượng ajax.

Sau đó, bạn chỉ có thể quay lại finalResultsmà không có thời gian, và các cuộc gọi đệ quy và ban đầu readFileRowcần đến awaitsự trở lại này.

Tôi cũng không rành lắm về lời hứa và mã hóa không đồng bộ nhưng đây là cách tôi đã làm những điều tương tự trước đây.

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

Thay vì thực hiện các cuộc gọi đồng thời (đợi cho đến khi yêu cầu trả lại và chỉ sau đó gọi đến cuộc gọi tiếp theo), bạn có thể gọi chúng song song bằng cách sử dụng Promise.all .

Mặc dù mã bên dưới hoàn toàn không sử dụng mã của bạn (vì tôi không thể làm cho nó thực sự hoạt động), nhưng nó cho thấy cách thức hoạt động của mã. Nếu nó không phản ánh 100% trường hợp của bạn, hãy cho tôi biết.

Logic là:

  1. Tìm nạp tổng số hàng để chúng tôi có thể biết chúng tôi nên tạo bao nhiêu yêu cầu - chúng tôi phải chờ yêu cầu này vì chúng tôi cần dữ liệu của nó cho phần còn lại của các yêu cầu.
  2. Tạo một mảng với tất cả các lời hứa và chuyển nó đến Promise.all. Các thensẽ trả lại tất cả các dữ liệu kết hợp.

Hãy cho tôi biết nếu ví dụ không rõ ràng ..

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


Điều này thực sự không giúp tôi nhiều. Tôi không nghĩ bạn nhất thiết sai, nhưng tôi không thể nhận được bất cứ bài học nào bạn đang dạy để áp dụng vào mã của tôi.
B. Allred

Đủ công bằng. Mặc dù đó là một điều quan trọng trong hoạt động khôn ngoan ..
Mosh Feu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.