Skip to content

Commit 942b571

Browse files
committed
Use XHR to load worker only if needed
Rather than always loading the pdf.worker.js source through XHR, first try creating a worker using the pdf.worker.js url. If that fails, use XHR. If that also fails, use a fake worker. Removed some earlier changes that ware unnecessary.
1 parent 92f1c14 commit 942b571

File tree

3 files changed

+185
-129
lines changed

3 files changed

+185
-129
lines changed

README.md

Lines changed: 81 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -186,65 +186,88 @@ We need to check if the viewer is initialized, before handling the event.
186186
+ // Ignore mousewheel event if pdfViewer isn't loaded
187187
+ if (!PDFViewerApplication.pdfViewer) return;
188188

189-
#### Load code for worker using AJAX
189+
#### Load code for worker using AJAX if needed
190190

191191
A [Web Worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) can't use code from
192-
a same-origin domain. The CORS headers don't apply (they do work in some browsers, but not in all).
193-
194-
To get around this, the source code of the worker is fetched using AJAX and presented as blob.
195-
196-
var WorkerTransport = (function WorkerTransportClosure() {
197-
function WorkerTransport(workerInitializedCapability, pdfDataRangeTransport) {
198-
+ /**
199-
+ * Needed because workers cannot load scripts outside of the current origin (as of firefox v45).
200-
+ * This patch does require the worker script to be served with a (Access-Control-Allow-Origin: *) header
201-
+ * @patch
202-
+ */
203-
+ globalScope.cachedJSDfd = null;
204-
+ this.loadWorkerXHR = function(url){
205-
+ if (globalScope.cachedJSDfd) { return globalScope.cachedJSDfd; }
206-
+ globalScope.cachedJSDfd = PDFJS.createPromiseCapability();
207-
+
208-
+ var xmlhttp;
209-
+ xmlhttp = new XMLHttpRequest();
210-
+
211-
+ xmlhttp.onreadystatechange = function(){
212-
+ if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
213-
+ var workerJSBlob = new Blob([xmlhttp.responseText], { type: 'text/javascript' });
214-
+ globalScope.cachedJSDfd.resolve(window.URL.createObjectURL(workerJSBlob));
215-
+ }
216-
+ };
217-
+
218-
+ xmlhttp.open('GET', url, true);
219-
+ xmlhttp.send();
220-
+ return globalScope.cachedJSDfd.promise;
221-
+ }
222-
223-
Instead of simply starting the worker, we need to get the code and than start it.
224-
225-
+ this.loadWorkerXHR(workerSrc).then(function(blob) {
226-
+ workerSrc = PDFJS.workerSrc = blob;
227-
+
228-
try {
229-
// Some versions of FF can't create a worker on localhost, see:
230-
// https://bugzilla.mozilla.org/show_bug.cgi?id=683280
231-
@@ -3589,11 +3618,16 @@
232-
return;
233-
} catch (e) {
234-
info('The worker has been disabled.');
235-
+ this.setupFakeWorker();
192+
a same-origin domain. The CORS headers don't apply.
193+
194+
he patch will cause pdf.js to first try to create the Worker the regular way, with a URL to the JavaScript source. If
195+
this fails, the source if fetched using AJAX and used to create an
196+
[object url](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL). If this also fails, pdf.js will go
197+
onto it's last resort by calling `setupFakeWorker()`.
198+
199+
+ /**
200+
+ * Needed because workers cannot load scripts outside of the current origin (as of firefox v45).
201+
+ * This patch does require the worker script to be served with a (Access-Control-Allow-Origin: *) header
202+
+ * @patch
203+
+ */
204+
+ var loadWorkerXHR = function(){
205+
+ var url = PDFJS.workerSrc;
206+
+ var jsdfd = PDFJS.createPromiseCapability();
207+
+
208+
+ if (url.match(/^blob:/) || typeof URL.createObjectURL === 'undefined') {
209+
+ jsdfd.reject(); // Failed loading using blob
210+
+ }
211+
+
212+
+ var xmlhttp;
213+
+ xmlhttp = new XMLHttpRequest();
214+
+
215+
+ xmlhttp.onreadystatechange = function(){
216+
+ if (xmlhttp.readyState != 4) return;
217+
+
218+
+ if (xmlhttp.status == 200) {
219+
+ info('Loaded worker source through XHR.');
220+
+ var workerJSBlob = new Blob([xmlhttp.responseText], { type: 'text/javascript' });
221+
+ jsdfd.resolve(window.URL.createObjectURL(workerJSBlob));
222+
+ } else {
223+
+ jsdfd.reject();
224+
+ }
225+
+ };
226+
+
227+
+ xmlhttp.open('GET', url, true);
228+
+ xmlhttp.send();
229+
+ return jsdfd.promise;
230+
+ }
231+
+
232+
+ var workerError = function() {
233+
+ loadWorkerXHR().then(function(blob) {
234+
+ PDFJS.workerSrc = blob;
235+
+ loadWorker();
236+
+ }, function() {
237+
+ this.setupFakeWorker();
238+
+ }.bind(this));
239+
+ }.bind(this);
240+
+
241+
242+
- if (!globalScope.PDFJS.disableWorker && typeof Worker !== 'undefined') {
243+
+ var loadWorker = function() {
244+
var workerSrc = PDFJS.workerSrc;
245+
if (!workerSrc) {
246+
error('No PDFJS.workerSrc specified');
247+
@@ -3559,6 +3603,8 @@
248+
// Some versions of FF can't create a worker on localhost, see:
249+
// https://bugzilla.mozilla.org/show_bug.cgi?id=683280
250+
var worker = new Worker(workerSrc);
251+
+ worker.onerror = workerError;
252+
+
253+
var messageHandler = new MessageHandler('main', worker);
254+
this.messageHandler = messageHandler;
255+
256+
@@ -3589,11 +3635,16 @@
257+
return;
258+
} catch (e) {
259+
info('The worker has been disabled.');
260+
+ workerError();
261+
}
262+
- }
263+
+ }.bind(this);
264+
// Either workers are disabled, not supported or have thrown an exception.
265+
// Thus, we fallback to a faked worker.
266+
- this.setupFakeWorker();
267+
+ if (!globalScope.PDFJS.disableWorker && typeof Worker !== 'undefined') {
268+
+ loadWorker();
269+
+ } else {
270+
+ this.setupFakeWorker();
271+
+ }
236272
}
237-
+
238-
+ }.bind(this));
239-
}
240-
241-
As the worker is started async, we only start the worker on an error, when the browser doesn't support web workers or
242-
when it's explicitly set that we don't want to use the web worker api.
243-
244-
// Either workers are disabled, not supported or have thrown an exception.
245-
// Thus, we fallback to a faked worker.
246-
- this.setupFakeWorker();
247-
+ if (globalScope.PDFJS.disableWorker || typeof Worker === 'undefined') {
248-
+ this.setupFakeWorker();
249-
+ }
250273

pdf.js

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,7 @@ PDFJS.build = 'c9a7498';
10861086
'use strict';
10871087

10881088
var globalScope = (typeof window === 'undefined') ? this : window;
1089+
10891090
var isWorker = (typeof window === 'undefined');
10901091

10911092
var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
@@ -3535,59 +3536,75 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
35353536
*/
35363537
var WorkerTransport = (function WorkerTransportClosure() {
35373538
function WorkerTransport(workerInitializedCapability, pdfDataRangeTransport) {
3539+
this.pdfDataRangeTransport = pdfDataRangeTransport;
3540+
this.workerInitializedCapability = workerInitializedCapability;
3541+
this.commonObjs = new PDFObjects();
3542+
3543+
this.loadingTask = null;
3544+
3545+
this.pageCache = [];
3546+
this.pagePromises = [];
3547+
this.downloadInfoCapability = createPromiseCapability();
3548+
35383549
/**
35393550
* Needed because workers cannot load scripts outside of the current origin (as of firefox v45).
35403551
* This patch does require the worker script to be served with a (Access-Control-Allow-Origin: *) header
35413552
* @patch
35423553
*/
3543-
globalScope.cachedJSDfd = null;
3544-
this.loadWorkerXHR = function(url){
3545-
if (globalScope.cachedJSDfd) { return globalScope.cachedJSDfd; }
3546-
globalScope.cachedJSDfd = PDFJS.createPromiseCapability();
3554+
var loadWorkerXHR = function(){
3555+
var url = PDFJS.workerSrc;
3556+
var jsdfd = PDFJS.createPromiseCapability();
3557+
3558+
if (url.match(/^blob:/) || typeof URL.createObjectURL === 'undefined') {
3559+
jsdfd.reject(); // Failed loading using blob
3560+
}
35473561

35483562
var xmlhttp;
35493563
xmlhttp = new XMLHttpRequest();
35503564

35513565
xmlhttp.onreadystatechange = function(){
3552-
if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
3566+
if (xmlhttp.readyState != 4) return;
3567+
3568+
if (xmlhttp.status == 200) {
3569+
info('Loaded worker source through XHR.');
35533570
var workerJSBlob = new Blob([xmlhttp.responseText], { type: 'text/javascript' });
3554-
globalScope.cachedJSDfd.resolve(window.URL.createObjectURL(workerJSBlob));
3571+
jsdfd.resolve(window.URL.createObjectURL(workerJSBlob));
3572+
} else {
3573+
jsdfd.reject();
35553574
}
35563575
};
35573576

35583577
xmlhttp.open('GET', url, true);
35593578
xmlhttp.send();
3560-
return globalScope.cachedJSDfd.promise;
3579+
return jsdfd.promise;
35613580
}
35623581

3563-
this.pdfDataRangeTransport = pdfDataRangeTransport;
3564-
this.workerInitializedCapability = workerInitializedCapability;
3565-
this.commonObjs = new PDFObjects();
3566-
3567-
this.loadingTask = null;
3568-
3569-
this.pageCache = [];
3570-
this.pagePromises = [];
3571-
this.downloadInfoCapability = createPromiseCapability();
3582+
var workerError = function() {
3583+
loadWorkerXHR().then(function(blob) {
3584+
PDFJS.workerSrc = blob;
3585+
loadWorker();
3586+
}, function() {
3587+
this.setupFakeWorker();
3588+
}.bind(this));
3589+
}.bind(this);
35723590

35733591
// If worker support isn't disabled explicit and the browser has worker
35743592
// support, create a new web worker and test if it/the browser fullfills
35753593
// all requirements to run parts of pdf.js in a web worker.
35763594
// Right now, the requirement is, that an Uint8Array is still an Uint8Array
35773595
// as it arrives on the worker. Chrome added this with version 15.
3578-
if (!globalScope.PDFJS.disableWorker && typeof Worker !== 'undefined') {
3596+
var loadWorker = function() {
35793597
var workerSrc = PDFJS.workerSrc;
35803598
if (!workerSrc) {
35813599
error('No PDFJS.workerSrc specified');
35823600
}
35833601

3584-
this.loadWorkerXHR(workerSrc).then(function(blob) {
3585-
workerSrc = PDFJS.workerSrc = blob;
3586-
35873602
try {
35883603
// Some versions of FF can't create a worker on localhost, see:
35893604
// https://bugzilla.mozilla.org/show_bug.cgi?id=683280
35903605
var worker = new Worker(workerSrc);
3606+
worker.onerror = workerError;
3607+
35913608
var messageHandler = new MessageHandler('main', worker);
35923609
this.messageHandler = messageHandler;
35933610

@@ -3618,14 +3635,14 @@ var WorkerTransport = (function WorkerTransportClosure() {
36183635
return;
36193636
} catch (e) {
36203637
info('The worker has been disabled.');
3621-
this.setupFakeWorker();
3638+
workerError();
36223639
}
3623-
3624-
}.bind(this));
3625-
}
3640+
}.bind(this);
36263641
// Either workers are disabled, not supported or have thrown an exception.
36273642
// Thus, we fallback to a faked worker.
3628-
if (globalScope.PDFJS.disableWorker || typeof Worker === 'undefined') {
3643+
if (!globalScope.PDFJS.disableWorker && typeof Worker !== 'undefined') {
3644+
loadWorker();
3645+
} else {
36293646
this.setupFakeWorker();
36303647
}
36313648
}

0 commit comments

Comments
 (0)