Przeglądaj źródła

采用发布/订阅模式异步加载文件,以提高预览的稳定性和速度

sunyj 9 lat temu
rodzic
commit
4b18741e2c

+ 2 - 0
src/main/webapp/WEB-INF/views/preview2.html

@@ -66,6 +66,8 @@
 
 <script src="static/lib/pdf.js/build/pdf.js"></script>
 <script src="static/lib/jquery/jquery.min.js"></script>
+<script src="static/lib/jquery/ba-tiny-pubsub.min.js"></script>
+<script src="static/js/util/utils.js"></script>
 <script src="static/js/preview/utils.js"></script>
 <script src="static/js/preview2/app.js"></script>
 </html>

+ 200 - 139
src/main/webapp/resources/js/preview2/app.js

@@ -6,8 +6,8 @@ var ctx = canvas.getContext('2d');
 // 隐藏的iframe,用于加载pdf,以便打印(pdf.js自带的打印有问题)
 var hiddenFrame = document.getElementById("hiddenFrame");
 
-// pdf文件的路径
-var url;
+// 能打印的最大页数(页数超过,需要先下载pdf,再打印)
+var PRINT_MAX_PAGE_SIZE = 500;
 var pdfDoc;
 // 页码
 var pageIndex;
@@ -21,8 +21,10 @@ var winHeight;
 var winWidth;
 // hiddenFrame是否加载成功
 var hiddenFrameLoaded = false;
-// 将要打印的总的pdf相对路径
-var pdfPath;
+// 将要打印的总的pdf(整个文档,而不是某一页的pdf)相对路径
+var wholePdfPath;
+// 某一页pdf文件的路径
+var pagedPdfPath;
 // 参数打印类型,可能为PRINT、PREVIEW
 var printType = getParameter("printType");
 
@@ -34,35 +36,6 @@ if (printType == 'PRINT') {
 	printPdf();
 }
 
-// 上页
-$("#prev").click(prevPage);
-
-// 下页
-$("#next").click(nextPage);
-
-// 手动输入页码
-$("#pageIndex").keypress(function(event) {
-	if (!pdfDoc) {
-		return;
-	}
-	// 按Enter键
-	if (event.keyCode == 13) {
-		var value = document.getElementById("pageIndex").value;
-		// 以非0开头的整数
-		var regExp = /^([1-9]+\d*)$/;
-		if (regExp.test(value) && value >= 1 && value <= pageSize) {
-			if (value == pageIndex) {
-				return;
-			}
-			url = url.replace(pageIndex + ".pdf", value + ".pdf");
-			pageIndex = value;
-			getDocument();
-		} else {
-			document.getElementById("pageIndex").value = pageIndex;
-		}
-	}
-});
-
 // 缩小,最小不小于原大小的0.2/1.2倍
 $("#zoomOut").click(function() {
 	if (scale >= 0.2) {
@@ -87,42 +60,72 @@ $("#scaleSelect").change(function() {
 	renderPage();
 });
 
+// 上页
+$("#prev").click(prevPage);
+
+// 下页
+$("#next").click(nextPage);
+
+// 手动输入页码
+$("#pageIndex").keypress(
+		function(event) {
+			if (!pdfDoc) {
+				return;
+			}
+			// 按Enter键
+			if (event.keyCode == 13) {
+				var value = document.getElementById("pageIndex").value;
+				// 以非0开头的整数
+				var regExp = /^([1-9]+\d*)$/;
+				if (regExp.test(value) && value >= 1 && value <= pageSize) {
+					if (value == pageIndex) {
+						return;
+					}
+					pagedPdfPath = pagedPdfPath.replace(pageIndex + ".pdf",
+							value + ".pdf");
+					pageIndex = value;
+					loadPagedPdf(pagedPdfPath);
+				} else {
+					document.getElementById("pageIndex").value = pageIndex;
+				}
+			}
+		});
+
 // 打印
 $("#print").click(function() {
 	if (!pdfDoc) {
 		return;
 	}
 	printPdf();
-	// console.log("1--loaded.." + hiddenFrameLoaded);
-	// if (hiddenFrameLoaded) {
-	// hiddenFrame.contentWindow.print();
-	// } else {
-	// console.log("2--loaded.." + hiddenFrameLoaded);
-	// }
 });
 
 // 下载pdf
-$("#downloadPdf").click(function() {
-	if (!pdfDoc) {
-		return;
-	}
-	// 检查文件状态,直到其可用
-	var valid;
-	while (!valid) {
-		valid = getGeneratedPdfOrXlsInformation("pdf")
-		sleep(1000);
-	}
-	window.location = downloadUrl("pdf");
-});
+$("#downloadPdf")
+		.click(
+				function() {
+					if (!pdfDoc) {
+						return;
+					}
+					// 检查文件状态,直到其可用
+					var valid;
+					if (!valid) {
+						setTimeout(
+								"valid = getGeneratedPdfOrXlsInformation('pdf').valid;console.log(valid)",
+								1000);
+						// valid = getGeneratedPdfOrXlsInformation("pdf").valid;
+						// sleep(1000);
+					}
+					window.location = downloadUrl("pdf");
+				});
 
 // 下载纯数据excel
 $("#downloadExcelWithOnlyData").click(function() {
 	if (!pdfDoc) {
 		return;
 	}
-	var valid;
-	while (!valid) {
-		valid = getGeneratedPdfOrXlsInformation("xls")
+	var size;
+	while (!size) {
+		size = getGeneratedPdfOrXlsInformation("xls").size;
 		sleep(1000);
 	}
 	window.location = downloadUrl("xls_with_only_data");
@@ -166,41 +169,69 @@ function getWindowWidth() {
 /**
  * 打印
  */
-// TODO delete 为hiddenFrame绑定事件,一旦pdf加载成功,修改hiddenFrameLoaded值
 function printPdf() {
-	if (pageSize > 1000) {
+	if (pageSize > PRINT_MAX_PAGE_SIZE) {
 		alert("文件过大,建议先下载到本地,再进行打印");
 		return;
 	}
-	var valid;
-	while (!valid) {
-		valid = getGeneratedPdfOrXlsInformation("pdf")
-		sleep(1000);
-	}
-	while (!hiddenFrameLoaded) {
-		console.log(Date.now() + " not loaded yet");
-		sleep(1000);
+	// 判断是否存在
+	// var size;
+	// while (!size) {
+	// size = getGeneratedPdfOrXlsInformation("pdf").valid;
+	// sleep(1000);
+	// }
+	if (!hiddenFrameLoaded) {
+		alert("正在生成文档");
+		console.log(new Date().format() + " ---- 需打印的文档未生成,正在生成文档");
+		// 订阅信号 "hiddenFrameLoaded",等待整个pdf加载完成
+		console.log(new Date().format() + " ---- subscribed hiddenFrameLoaded");
+		$.subscribe("hiddenFrameLoaded", print);
+	} else {
+		alert("正在加载文档");
+		console.log(new Date().format() + " ---- start print...");
+		hiddenFrame.contentWindow.print();
 	}
-	console.log(Date.now() + " loaded");
+}
+
+/**
+ * 调用浏览器的打印方法并取消订阅信号 "hiddenFrameLoaded"
+ */
+function print() {
+	console.log(new Date().format()
+			+ " ---- received and unsubscribe hiddenFrameLoaded");
+	$.unsubscribe("hiddenFrameLoaded", print);
 	hiddenFrame.contentWindow.print();
-	// console.log("1----" + hiddenFrameLoaded);
-	// if (!hiddenFrameLoaded) {
-	// hiddenFrame.src = pdfPath;
-	// // IE的onload事件
-	// if (hiddenFrame.attachEvent) {
-	// hiddenFrame.attachEvent("onload", function() {
-	// hiddenFrameLoaded = true;
-	// hiddenFrame.contentWindow.print();
-	// })
-	// } else {
-	// hiddenFrame.onload = function() {
-	// hiddenFrameLoaded = true;
-	// hiddenFrame.contentWindow.print();
-	// };
-	// }
-	// } else {
-	// hiddenFrame.contentWindow.print();
-	// }
+	alert("文档加载完成");
+}
+
+/**
+ * 获取预览的pdf文档数据,完成后加载整个文档
+ * 
+ * @param pagedPdfPath
+ *            需要进行预览的分页pdf相对路径
+ * @param ifPreloadWholePdf
+ *            渲染之后,是否预加载整个文档
+ */
+function loadPagedPdf(pagedPdfPath, ifPreloadWholePdf) {
+	// var dfd = $.Deferred();
+	PDFJS.getDocument(pagedPdfPath).then(
+			function(pdfDoc_) {
+				// 更新页码
+				document.getElementById('pageIndex').value = pageIndex;
+				pdfDoc = pdfDoc_;
+				// Initial/first page rendering
+				renderPage();
+				// 第一页文档渲染完成后,再加载整个文档
+				if (ifPreloadWholePdf) {
+					console.log(new Date().format()
+							+ " ---- subscribed renderTaskFinished");
+					$.subscribe("renderTaskFinished", loadWholePdf);
+				}
+				// $.when(rend("getDocument promised");
+				// dfd.resolve();
+				// });
+			});
+	// return dfd.promise;
 }
 
 /**
@@ -208,7 +239,8 @@ function printPdf() {
  */
 function loadData() {
 	var loadPdfDataUrl = "print/loadPdfData" + window.location.search;
-	if (printType == "PREVIEW") {
+	// 未传参数printType或者为PREVIEW,则先获取第一页pdf
+	if (!printType || printType == "PREVIEW") {
 		loadPdfDataUrl = loadPdfDataUrl + "&pageIndex=" + 1;
 	}
 	$.ajax({
@@ -217,19 +249,20 @@ function loadData() {
 		url : loadPdfDataUrl,
 		success : function(data) {
 			// 返回的pdf文件路径
-			pdfPath = data.pdfPath;
+			wholePdfPath = data.pdfPath;
 			if (!pageIndex) {
 				pageIndex = 1;
 			}
 			// 第一页的pdf文件路径
-			url = pdfPath.replace(".pdf", "_" + pageIndex + ".pdf");
+			pagedPdfPath = wholePdfPath.replace(".pdf", "_" + pageIndex
+					+ ".pdf");
 			pageSize = data.pageSize;
 			document.getElementById('pageSize').textContent = pageSize;
 			document.title = getParameter("reportName");
 			// 加载第一页文档
-			getDocument();
-			// 预加载整个文档
-			preloadWholePdf();
+			loadPagedPdf(pagedPdfPath, true);
+			// $.when(getDocument()).done(loadWholePdf);
+			// console.log(renderTask._internalRenderTask.running);
 		},
 		error : function(XMLHttpRequest) {
 			var viewerContainer = document.getElementById("viewerContainer");
@@ -246,37 +279,48 @@ function loadData() {
 };
 
 /**
- * 获取预览的pdf文档数据
+ * 预加载整个pdf(大于PRINT_MAX_PAGE_SIZE页,不加载)文件,以提高后续打印速度
  */
-function getDocument() {
-	PDFJS.getDocument(url).then(function(pdfDoc_) {
-		// 更新页码
-		document.getElementById('pageIndex').value = pageIndex;
-		pdfDoc = pdfDoc_;
-		// Initial/first page rendering
-		renderPage();
-	});
-}
-
-/**
- * 预加载整个pdf(大于1000页,不加载)文件,以提高后续打印速度
- */
-function preloadWholePdf() {
-	if (pageSize > 1000) {
-		console.log("文件过大,建议先下载到本地,再进行打印");
+function loadWholePdf() {
+	console.log(new Date().format()
+			+ " ---- received and unsubscribe renderTaskFinished");
+	$.unsubscribe("renderTaskFinished", loadWholePdf);
+	// 渲染完成后延迟一小段时间预加载整个文档
+	sleep(500);
+	if (pageSize > PRINT_MAX_PAGE_SIZE) {
+		console.log(new Date().format() + " ---- 文件过大,建议先下载到本地,再进行打印");
+		hiddenFrameLoaded = true;
 		return;
 	}
-	hiddenFrame.src = pdfPath;
+	// 绑定onload事件
 	hiddenFrame.onload = function() {
-		// 加载失败(pdf文件不存在,404错误),title不为null
+		// 加载失败时(pdf文件不存在,404错误),title不为null
+		// 此时等待一段时间再重新加载
 		if (hiddenFrame.contentDocument.title) {
-			console.log(Date.now() + " " + hiddenFrame.contentDocument.title);
-			hiddenFrame.src = pdfPath;
-			sleep(2000);
+			console.log(new Date().format() + " ---- file not exist");
+			console.log(new Date().format() + " ---- hiddenFrame load failed");
+			// 等待时间为10*页数 ms(需要在500ms~5000ms之间)
+			var waitTime = pageSize * 10;
+			waitTime = waitTime > 5000 ? 5000 : waitTime;
+			waitTime = waitTime < 500 ? 500 : waitTime;
+			console.log(new Date().format() + " ---- wait " + waitTime + "ms");
+			setTimeout("hiddenFrame.src = wholePdfPath", waitTime);
+			console.log(new Date().format() + " ---- hiddenFrame reloading...");
+
 		} else {
+			console.log(new Date().format()
+					+ " ---- hiddenFrame load successed");
 			hiddenFrameLoaded = true;
+			console
+					.log(new Date().format()
+							+ " ---- publish hiddenFrameLoaded");
+			// 发布信号 "hiddenFrameLoaded"
+			$.publish("hiddenFrameLoaded");
 		}
 	};
+	// 开始加载
+	console.log(new Date().format() + " ---- hiddenFrame loading...");
+	hiddenFrame.src = wholePdfPath;
 }
 
 /**
@@ -287,25 +331,38 @@ function renderPage() {
 		return;
 	}
 	// 每个pdf只有一页
-	pdfDoc.getPage(1).then(function(page) {
-		if (!scale || scale == "auto") {
-			// 调整为适合的宽度
-			scale = getScale(page, 0.75);
-		} else if (scale == "page_width") {
-			// 调整pdf显示的宽度接近窗口宽度
-			scale = getScale(page, 0.95);
-		}
-		var viewport = page.getViewport(scale);
-		canvas.height = viewport.height;
-		canvas.width = viewport.width;
-		// Render PDF page into canvas context
-		var renderContext = {
-			canvasContext : ctx,
-			viewport : viewport
-		};
-		// 开始渲染
-		var renderTask = page.render(renderContext);
-	});
+	pdfDoc.getPage(1).then(
+			function(page) {
+				if (!scale || scale == "auto") {
+					// 调整为适合的宽度
+					scale = getScale(page, 0.75);
+				} else if (scale == "page_width") {
+					// 调整pdf显示的宽度接近窗口宽度
+					scale = getScale(page, 0.95);
+				}
+				var viewport = page.getViewport(scale);
+				canvas.height = viewport.height;
+				canvas.width = viewport.width;
+				// Render PDF page into canvas context
+				var renderContext = {
+					canvasContext : ctx,
+					viewport : viewport
+				};
+				// 开始渲染
+				var renderTask = page.render(renderContext);
+				$.when(renderTask).done(
+						function() {
+							// 渲染完成后,发布信号 "renderTaskFinished"
+							console.log(new Date().format()
+									+ " ---- renderTask finished");
+							console.log(new Date().format()
+									+ " ---- publish renderTaskFinished");
+							$.publish("renderTaskFinished");
+							// var renderTaskRunning =
+							// renderTask._internalRenderTask.running;
+							// return !renderTaskRunning;
+						});
+			});
 }
 
 /**
@@ -332,8 +389,9 @@ function prevPage() {
 		return;
 	}
 	// 获取前一页的pdf
-	url = url.replace(pageIndex + ".pdf", (--pageIndex) + ".pdf");
-	getDocument();
+	pagedPdfPath = pagedPdfPath.replace(pageIndex + ".pdf", (--pageIndex)
+			+ ".pdf");
+	loadPagedPdf(pagedPdfPath);
 }
 
 /**
@@ -343,8 +401,9 @@ function nextPage() {
 	if (!pdfDoc || pageIndex >= pageSize) {
 		return;
 	}
-	url = url.replace(pageIndex + ".pdf", (++pageIndex) + ".pdf");
-	getDocument();
+	pagedPdfPath = pagedPdfPath.replace(pageIndex + ".pdf", (++pageIndex)
+			+ ".pdf");
+	loadPagedPdf(pagedPdfPath);
 }
 
 /**
@@ -365,18 +424,20 @@ function changeTextOfSelectScale() {
  *            pdf或者xls
  */
 function getGeneratedPdfOrXlsInformation(pdfOrXls) {
-	var valid;
+	var data;
 	$.ajax({
 		type : "get",
 		async : false,
 		url : "print/getGeneratedPdfOrXlsInformation" + window.location.search
 				+ "&pdfOrXls=" + pdfOrXls,
-		success : function(data) {
-			console.log(data);
-			valid = data.valid;
+		success : function(result) {
+			console
+					.log(new Date().format() + " ---- "
+							+ JSON.stringify(result));
+			data = result;
 		}
 	});
-	return valid;
+	return data;
 }
 
 /**