-
Notifications
You must be signed in to change notification settings - Fork 182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimization: Caching library #2337
Comments
pdf.js is removed from memory when you destroy the Angular component. Instead, you can simply hide the this.showPDF = true;
setTimeout(() => this.src="/assets/my-favorite-pdf-file.pdf", 0); <ngx-extended-pdf-viewer [style.hidden]="!showPDF" [src]="src"> Note that this is pseudo-code - I didn't try it. If it works, please tell me, so I can fix the errors of my pseudo-code for the benefit of other users. |
It's not what we are looking for. We need something global in case of saving viewer. I'm trying to initialize it with ComponentFactoryResolver to save instance of library but it still re-launch(pdf-worker) and others and it's a bit harder to use. Main problem to avoid load library(from source from cache what ever) and avoid executing JS each time it need. Best behavior: load library(all source what needs), cache them and each time we invoke it be ready to show document as it waits for them. We need to understand if it possible. By our investigating it looks like not, at least with how we using library. |
There are checks preventing loading the Remains the worker. That's probably the most annoying file because it's so huge. After reading the How urgent is your issue? Are you ready to dive into the source code yourself? At the moment, I'm trying to catch up after my vacations, so I appreciate every help I can get! |
We are really interesting in it. Unfortunately I can't help with it. I tested again and can see that viewer-*.js and pdf-.js loads only first time. We are waiting for caching workers(pdf.worker-) and all you can do as soon as you can implement it. If you can mention in some way with ready state of this it will be great. Thank you in advance |
Issue #2329 is doing the exact opposite: they noticed I've implemented a memory leak, so the garbage collector can't remove the JavaScript resources. I'll tackle #2329 first. It might make your issue worse. Here's something you can try: you can load the JavaScript files yourself. Actually you can even load the worker file yourself, but that means the worker is executed in the main thread, so it reduces the rendering performance. It depends on the use-case which tradeoff is worse. private loadViewer(): void {
globalThis['ngxZone'] = this.ngZone;
this.ngZone.runOutsideAngular(() => {
this.needsES5().then((needsES5) => {
const viewerPath = this.getPdfJsPath('viewer', needsES5);
const script = this.createScriptElement(viewerPath);
document.getElementsByTagName('head')[0].appendChild(script);
});
});
}
private loadPdfJs() {
globalThis['ngxZone'] = this.ngZone;
this.ngZone.runOutsideAngular(() => {
if (!globalThis['pdfjs-dist/build/pdf']) {
this.needsES5().then((needsES5) => {
if (needsES5) {
if (!pdfDefaultOptions.needsES5) {
console.log(
"If you see the error message \"expected expression, got '='\" above: you can safely ignore it as long as you know what you're doing. It means your browser is out-of-date. Please update your browser to benefit from the latest security updates and to enjoy a faster PDF viewer."
);
}
pdfDefaultOptions.needsES5 = true;
console.log('Using the ES5 version of the PDF viewer. Your PDF files show faster if you update your browser.');
}
if (this.minifiedJSLibraries && !needsES5) {
if (!pdfDefaultOptions.workerSrc().endsWith('.min.mjs')) {
const src = pdfDefaultOptions.workerSrc();
pdfDefaultOptions.workerSrc = () => src.replace('.mjs', '.min.mjs');
}
}
const pdfJsPath = this.getPdfJsPath('pdf', needsES5);
if (pdfJsPath.endsWith('.mjs')) {
const src = pdfDefaultOptions.workerSrc();
if (src.endsWith('.js')) {
pdfDefaultOptions.workerSrc = () => src.substring(0, src.length - 3) + '.mjs';
}
}
const script = this.createScriptElement(pdfJsPath);
script.onload = () => {
if (!(globalThis as any).webViewerLoad) {
this.loadViewer();
}
};
document.getElementsByTagName('head')[0].appendChild(script);
});
} else if (!(globalThis as any).webViewerLoad) {
this.loadViewer();
}
});
}
private createScriptElement(sourcePath: string): HTMLScriptElement {
const script = document.createElement('script');
script.async = true;
script.type = sourcePath.endsWith('.mjs') ? 'module' : 'text/javascript';
this.pdfCspPolicyService.addTrustedJavaScript(script, sourcePath);
return script;
} In your application, you can simplify the code a lot. You don't need all the options a general-purpose library needs. |
I've got an idea how to improve performance in version 21. If everything goes according to plan, I'm going to move the code loading and managing the base library into a service, so it doesn't have to be loaded every time you navigate from page to page. |
It will be great. Looking forward for your news. Thanks for replying here. As for the error with old version of chrome with new version. Do you have a plan to fix it? Or just throw error with event?. Unfortunately we still have old users with old browsers and need to support them. For now we have workaround with window.onerror but we understand that it's not the best idea. Could you share you thoughts? |
Which bug are you referring to? Maybe |
Yes, about this bug. I tried to polyfill it and it's isn't working. I tried to add to angular code something like function promiseWithResolvers() {
let resolve;
let reject;
const promise = new Promise(
(res, rej) => {
// Executed synchronously!
resolve = res;
reject = rej;
});
return {promise, resolve, reject};
} But it didn't work as expected(nothing changed). Don't know is it read code and can work(you can test it) |
That's pretty much the approach I'd use, just slightly different - maybe that's why it's not working? I'd add these lines to the module file or to the constructor of the component using Promise.promiseWithResolvers() = function() {
let resolve;
let reject;
const promise = new Promise(
(res, rej) => {
// Executed synchronously!
resolve = res;
reject = rej;
});
return {promise, resolve, reject};
} |
BTW, if everything fails, there's always the option to add the attribute |
…ice so multiple instances can use the JavaScript files without reloading them; move objects from `globalThis` to `PdfViewerApplication`; stop using `ngZone.runOutsideAngular()` to make it easier to use the viewer without zone.js
Have a look at version 21.0.0-alpha.0. I'd be very surprised if it's not full of bugs - but it works surprisingly good, and jumping between the demos of the showcase seems to be considerably faster. |
I have already tested it and have this moments:
As for loading process, it's hard to say that it loads faster, need to re-test it again after your fixes. Thanks in advance |
…ding the JavaScript files to a service so multiple instances can use the JavaScript files without reloading them; move objects from `globalThis` to `PdfViewerApplication`; stop using `ngZone.runOutsideAngular()` to make it easier to use the viewer without zone.js
…ding the JavaScript files to a service so multiple instances can use the JavaScript files without reloading them; move objects from `globalThis` to `PdfViewerApplication`; stop using `ngZone.runOutsideAngular()` to make it easier to use the viewer without zone.js
Thanks for testing! This helps me a lot! |
To dos:
|
I'm afraid I can't reproduce your toolbar bug. I've throttled network speed to 1 mbit/s, so loading too a long time, and ran the toolbar demo (the local counterpart of https://pdfviewer.net/extended-pdf-viewer/hiding-buttons). I didn't see any button that shouldn't be there. This is my screenshot, taken while the JavaScript files were still loading: |
…tivated or deactivated in an existing viewer when showing another document
…rom `globalThis` to `PdfViewerApplication`
…dow` object; use a sensible default value for `filenameForDownload`; stop throwing errors when closing a dialog that's already closed (happens sometimes when `ngOnChanges` fires)
…ails so they don't need to pollute the `window` object;
…rom `globalThis` to `PdfViewerApplication`
…dow` object; use a sensible default value for `filenameForDownload`; stop throwing errors when closing a dialog that's already closed (happens sometimes when `ngOnChanges` fires)
…ails so they don't need to pollute the `window` object;
…'t access the `window` object
…'t access the `window` object
…e global namespace
…ails so they don't need to pollute the `window` object
…e global namespace
…ails so they don't need to pollute the `window` object
…interface `PasswordPrompt` (now it includes the `open` and `close` methods)
…uishable from the other find results when `highlight all` is selected
I believe version 21.0.0-alpha.9 delivers a pretty stable implementation of your feature. Enjoy! |
2024-07-16 12-02-11.webm |
…pplicationOptions
…stance of `PDFViewerApplication`
Version 21.0.0-beta.1 ships with more improvements. Earlier versions accidentally loaded the worker file twice. Now everything should work as intended. Maybe it's even possible to re-use the worker - but let's address this in a future ticket. |
I have a question-request. How to cache/optimize library sources and loads. We use pdf library to view pdf. We have component which re-initialize a lot of times during user session. And every time we need to load js files. How to optimize this process? Is it possible to load only first time? We understand that js files caching and next time it's load from browser cache. But we still need time to process js. What is your recommendation for best optimization, reusabillity component? Thanks in advance
The text was updated successfully, but these errors were encountered: