我前段時間面對同樣的問題(在爲攝影師服務時,使用角度)。
問題不是關於RxJS或角度,而是關於瀏覽器本身 - 它不是針對以這種方式顯示大量大圖像進行優化的。
首先,如果你需要顯示大量的圖片(沒關係是本地或遠程文件):
- 顯示(加載速度更快,不需要調整尺寸,更低的內存消耗)之前調整它們的大小。
- 如果可以 - 只顯示可見圖像(否則頁面會非常慢,直到所有圖像都會被加載)。檢查這個答案:How do I get the x and y positions of an element in an AngularJS directive原本
trackVisibility
被寫爲僅當它們變得可見時才顯示圖像。
關於從本地文件顯示圖像,事情更加複雜:
在你的情況要裝入文件數據的URL,並有一個問題:你3 MB提到的70張圖片每個會消耗至少2.1 Gb的RAM(實際上更多,並且不經意間會影響性能)
第一個建議是 - 如果您可以: 。第二:如果您只需要縮略圖 - 在顯示圖像之前在本地調整圖像大小(使用畫布)。如果對你來說很重要的話,會出現抗鋸齒問題 - 請看下面描述的降壓技術:Html5 canvas drawImage: how to apply antialiasing如果你支持iOS,那麼畫布尺寸限制可能會有問題,所以你需要以某種方式檢測它。 (這兩個問題都在下面的例子中解決)
最後一個:如果你需要爲許多圖像創建縮略圖 - 不要一次做這個,而是 - 安排工作事件循環(否則瀏覽器不會在調整圖像大小時有反應)。爲了獲得更好的性能,請按順序執行此操作(對於所有映像不要並行執行),這可能聽起來很奇怪 - 但速度會更快(由於內存消耗過低,同時讀取的磁盤空間更少)。
總結:
- 使用上述
trackVisibility
指令,只顯示可見光圖像
- 不要使用,數據的URL特別是對於大的圖像。
- 創建調整大小的縮略圖,顯示他們
庫之前,你可能會發現實現這個有用的:這樣做縮略圖
粗糙的代碼示例(大部分代碼都是從工作項目中複製而來的 - 所以預計會有效。canvasToJpegBlob
和makeThumbnail
剛纔寫,並沒有經過測試,所以可以有小的失誤):
function loadImage(imagePath) {
return Rx.Observable.create(function(observer) {
var img = new Image();
img.src = imagePath;
image.onload = function() {
observer.onNext(image);
observer.onCompleted();
}
image.onError = function(err) {
observer.onError(err);
}
});
}
// canvas edge cases detection
var maxDimm = 32000;
var ios5 = false, ios3 = false;
(function() {
if (navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') > 0) {
maxDimm = 8000;
} else {
var canvas = document.createElement('canvas');
canvas.width = 1024 * 3;
canvas.height = 1025;
if (canvas.toDataURL('image/jpeg') === 'data:,') {
ios3 = true;
} else {
canvas = document.createElement('canvas');
canvas.width = 1024 * 5;
canvas.height = 1025;
if (canvas.toDataURL('image/jpeg') === 'data:,') {
ios5 = true;
}
}
}
}());
function stepDown(src, width, height) {
var
steps,
resultCanvas = document.createElement('canvas'),
srcWidth = src.width,
srcHeight = src.height,
context;
resultCanvas.width = width;
resultCanvas.height = height;
if ((srcWidth/width) > (srcHeight/height)) {
steps = Math.ceil(Math.log(srcWidth/width)/Math.log(2));
} else {
steps = Math.ceil(Math.log(srcHeight/height)/Math.log(2));
}
if (steps <= 1) {
context = resultCanvas.getContext('2d');
context.drawImage(src, 0, 0, width, height);
} else {
var tmpCanvas = document.createElement('canvas');
var
currentWidth = width * Math.pow(2, steps - 1),
currentHeight = height * Math.pow(2, steps - 1),
newWidth = currentWidth,
newHeight = currentHeight;
if (ios3 && currentWidth * currentHeight > 3 * 1024 * 1024) {
newHeight = 1024 * Math.sqrt(3 * srcHeight/srcWidth);
newWidth = newHeight * srcWidth/srcHeight;
} else {
if (ios5 && currentWidth * currentHeight > 5 * 1024 * 1024) {
newHeight = 1024 * Math.sqrt(5 * srcHeight/srcWidth);
newWidth = newHeight * srcWidth/srcHeight;
} else {
if (currentWidth > maxDimm || currentHeight > maxDimm) {
if (currentHeight > currentWidth) {
newHeight = maxDimm;
newWidth = maxDimm * currentWidth/currentHeight;
} else {
newWidth = maxDimm;
newHeight = maxDimm * currentWidth/currentHeight;
}
}
}
}
currentWidth = newWidth;
currentHeight = newHeight;
if ((currentWidth/width) > (currentHeight/height)) {
steps = Math.ceil(Math.log(currentWidth/width)/Math.log(2));
} else {
steps = Math.ceil(Math.log(currentHeight/height)/Math.log(2));
}
context = tmpCanvas.getContext('2d');
tmpCanvas.width = Math.ceil(currentWidth);
tmpCanvas.height = Math.ceil(currentHeight);
context.drawImage(src, 0, 0, srcWidth, srcHeight, 0, 0, currentWidth, currentHeight);
while (steps > 1) {
newWidth = currentWidth * 0.5;
newHeight = currentHeight * 0.5;
context.drawImage(tmpCanvas, 0, 0, currentWidth, currentHeight, 0, 0, newWidth, newHeight);
steps -= 1;
currentWidth = newWidth;
currentHeight = newHeight;
}
context = resultCanvas.getContext('2d');
context.drawImage(tmpCanvas, 0, 0, currentWidth, currentHeight, 0, 0, width, height);
}
return resultCanvas;
}
function canvasToJpegBlob(canvas) {
return Rx.Observable.create(function(observer) {
try {
canvas.toBlob(function(blob) {
observer.onNext(blob);
observer.onCompleted();
}, 'image/jpeg');
} catch (err) {
observer.onError(err);
}
});
}
function makeThumbnail(file) {
return Observable.defer(()=> {
const fileUrl = URL.createObjectURL(file);
return loadImage(fileUrl)
.map(image => {
const width = 200;
const height = image.height * width/image.width;
const thumbnailCanvas = stepDown(image, width, height);
URL.revokeObjectURL(fileUrl);
return thubnailCanvas;
})
.flatMap(canvasToJpegBlob)
.map(canvasBlob=>URL.createObjectURL(canvasBlob))
.map(thumbnailUrl => {
return {
file,
thumbnailUrl
}
})
});
}
老實說,它可能RxJS放慢你失望。 JS中的功能反應式編程非常好,但效率不高。 [我跑了一個測試](https://jsfiddle.net/pb2ra0c4/)使用[非常大的圖像](https://upload.wikimedia.org/wikipedia/commons/4/43/Very_Large_Array,_2012.jpg) (7360x4912或21.6 MB),並且在不使用任何其他框架時顯示大約需要1.5秒。 –
您可以上傳文件,創建縮略圖並顯示縮略圖,而不是將圖像大小調整爲200像素 – Ronnie
上傳文件在哪裏?通過網絡發送這些圖像到遠程服務器將是緩慢的...然後服務器將不得不調整它們,這將不會很快... – Roaders