diff --git a/src/openpgp.js b/src/openpgp.js
index 2d6b54af..8d0002fb 100644
--- a/src/openpgp.js
+++ b/src/openpgp.js
@@ -76,14 +76,12 @@ let asyncProxy; // instance of the asyncproxy
  */
 export async function initWorker({ path = 'openpgp.worker.js', n = 1, workers = [] } = {}) {
   if (workers.length || (typeof global !== 'undefined' && global.Worker && global.MessageChannel)) {
-    const proxy = new AsyncProxy({ path, n, workers, config });
-    const loaded = await proxy.loaded();
-    if (loaded) {
-      asyncProxy = proxy;
-      return true;
-    }
+    const proxy = new AsyncProxy();
+    await proxy.init({ path, n, workers, config });
+    asyncProxy = proxy;
+  } else {
+    throw new Error('Web Workers are not available');
   }
-  return false;
 }
 
 /**
diff --git a/src/worker/async_proxy.js b/src/worker/async_proxy.js
index 7a01e9da..286919d8 100644
--- a/src/worker/async_proxy.js
+++ b/src/worker/async_proxy.js
@@ -35,23 +35,25 @@ import packet from '../packet';
 
 
 /**
- * Initializes a new proxy and loads the web worker
+ * Creates a new async proxy
+ * @constructor
+ */
+function AsyncProxy() {}
+
+/**
+ * Initializes the proxy and loads the web worker
  * @param {String} path            The path to the worker or 'openpgp.worker.js' by default
  * @param {Number} n               number of workers to initialize if path given
  * @param {Object} config          config The worker configuration
  * @param {Array<Object>} worker   alternative to path parameter: web worker initialized with 'openpgp.worker.js'
- * @constructor
  */
-function AsyncProxy({ path = 'openpgp.worker.js', n = 1, workers = [], config } = {}) {
+AsyncProxy.prototype.init = async function({ path = 'openpgp.worker.js', n = 1, workers = [], config } = {}) {
   /**
    * Message handling
    */
   const handleMessage = workerId => event => {
     const msg = event.data;
     switch (msg.event) {
-      case 'loaded':
-        this.workers[workerId].loadedResolve(true);
-        break;
       case 'method-return':
         if (msg.err) {
           // fail
@@ -84,37 +86,21 @@ function AsyncProxy({ path = 'openpgp.worker.js', n = 1, workers = [], config }
     }
   }
 
-  let workerId = 0;
-  this.workers.forEach(worker => {
-    worker.loadedPromise = new Promise(resolve => {
-      worker.loadedResolve = resolve;
-    });
-    worker.requests = 0;
-    worker.onmessage = handleMessage(workerId++);
-    worker.onerror = e => {
-      worker.loadedResolve(false);
-      // eslint-disable-next-line no-console
-      console.error('Unhandled error in openpgp worker: ' + e.message + ' (' + e.filename + ':' + e.lineno + ')');
-      return false;
-    };
-
-    if (config) {
-      worker.postMessage({ event:'configure', config });
-    }
-  });
-
   // Cannot rely on task order being maintained, use object keyed by request ID to track tasks
   this.tasks = {};
   this.currentID = 0;
-}
 
-/**
- * Returns a promise that resolves when all workers have finished loading
- * @returns {Promise<Boolean>} Resolves to true if all workers have loaded succesfully; false otherwise
-*/
-AsyncProxy.prototype.loaded = async function() {
-  const loaded = await Promise.all(this.workers.map(worker => worker.loadedPromise));
-  return loaded.every(Boolean);
+  let workerId = 0;
+  await Promise.all(this.workers.map(worker => new Promise(async (resolve, reject) => {
+    worker.requests = 0;
+    worker.onmessage = handleMessage(workerId++);
+    worker.onerror = e => {
+      reject(new Error('Unhandled error in openpgp worker: ' + e.message + ' (' + e.filename + ':' + e.lineno + ')'));
+    };
+
+    await this.callWorker(worker, 'configure', config);
+    resolve();
+  })));
 };
 
 /**
@@ -132,7 +118,7 @@ AsyncProxy.prototype.getID = function() {
  */
 AsyncProxy.prototype.seedRandom = async function(workerId, size) {
   const buf = await crypto.random.getRandomBytes(size);
-  this.workers[workerId].postMessage({ event:'seed-random', buf }, util.getTransferables(buf, true));
+  this.workers[workerId].postMessage({ event: 'seed-random', buf }, util.getTransferables(buf, true));
 };
 
 /**
@@ -140,13 +126,7 @@ AsyncProxy.prototype.seedRandom = async function(workerId, size) {
  * @async
  */
 AsyncProxy.prototype.clearKeyCache = async function() {
-  await Promise.all(this.workers.map(worker => new Promise((resolve, reject) => {
-    const id = this.getID();
-
-    worker.postMessage({ id, event: 'clear-key-cache' });
-
-    this.tasks[id] = { resolve, reject };
-  })));
+  await Promise.all(this.workers.map(worker => this.callWorker(worker, 'clear-key-cache')));
 };
 
 /**
@@ -165,9 +145,7 @@ AsyncProxy.prototype.terminate = function() {
  * @returns {Promise}          see the corresponding public api functions for their return types
  * @async
  */
-AsyncProxy.prototype.delegate = function(method, options) {
-
-  const id = this.getID();
+AsyncProxy.prototype.delegate = async function (method, options) {
   const requests = this.workers.map(worker => worker.requests);
   const minRequests = Math.min(...requests);
   let workerId = 0;
@@ -177,15 +155,21 @@ AsyncProxy.prototype.delegate = function(method, options) {
     }
   }
 
-  return new Promise((resolve, reject) => {
-    const data = { id, event: method, options: packet.clone.clonePackets(options) };
-    const transferables = util.getTransferables(data, config.zero_copy);
-    // clone packets (for web worker structured cloning algorithm)
-    this.workers[workerId].postMessage(data, transferables);
-    this.workers[workerId].requests++;
+  const data = { options: packet.clone.clonePackets(options) };
+  const transferables = util.getTransferables(data, config.zero_copy);
+  const worker = this.workers[workerId];
+  worker.requests++;
+  const result = await this.callWorker(worker, method, data.options, transferables);
+  return packet.clone.parseClonedPackets(util.restoreStreams(result, options.streaming), method);
+};
 
-    // remember to handle parsing cloned packets from worker
-    this.tasks[id] = { resolve: data => resolve(packet.clone.parseClonedPackets(util.restoreStreams(data, options.streaming), method)), reject };
+AsyncProxy.prototype.callWorker = function(worker, method, options, transferables) {
+  return new Promise((resolve, reject) => {
+    const id = this.getID();
+
+    worker.postMessage({ id, method, options }, transferables);
+
+    this.tasks[id] = { resolve, reject };
   });
 };
 
diff --git a/src/worker/worker.js b/src/worker/worker.js
index f1a576e0..965db429 100644
--- a/src/worker/worker.js
+++ b/src/worker/worker.js
@@ -58,11 +58,7 @@ openpgp.crypto.random.randomBuffer.init(MAX_SIZE_RANDOM_BUFFER, randomCallback);
 self.onmessage = function(event) {
   var msg = event.data || {};
 
-  switch (msg.event) {
-    case 'configure':
-      configure(msg.config);
-      break;
-
+  switch (msg.method) {
     case 'seed-random':
       seedRandom(msg.buf);
 
@@ -75,7 +71,7 @@ self.onmessage = function(event) {
       break;
 
     default:
-      delegate(msg.id, msg.event, msg.options || {});
+      delegate(msg.id, msg.method, msg.options || {});
   }
 };
 
@@ -117,6 +113,11 @@ function getCachedKey(key) {
  * @param  {Object} options   The api function's options
  */
 function delegate(id, method, options) {
+  if (method === 'configure') {
+    configure(options);
+    response({ id, event: 'method-return' });
+    return;
+  }
   if (method === 'clear-key-cache') {
     Array.from(keyCache.values()).forEach(key => {
       if (key.isPrivate()) {
@@ -161,7 +162,3 @@ function response(event) {
   self.postMessage(event, openpgp.util.getTransferables(event.data, openpgp.config.zero_copy));
 }
 
-/**
- * Let the main window know the worker has loaded.
- */
-postMessage({ event: 'loaded' });
diff --git a/test/general/brainpool.js b/test/general/brainpool.js
index 9b4ae6b2..4d01a18a 100644
--- a/test/general/brainpool.js
+++ b/test/general/brainpool.js
@@ -347,7 +347,11 @@ tryTests('Brainpool Omnibus Tests @lightweight', omnibus, {
 tryTests('Brainpool Omnibus Tests - Worker @lightweight', omnibus, {
   if: typeof window !== 'undefined' && window.Worker && (openpgp.config.use_indutny_elliptic || openpgp.util.getNodeCrypto()),
   before: async function() {
-    await openpgp.initWorker({ path: '../dist/openpgp.worker.js' });
+    try {
+      await openpgp.initWorker({ path: '../dist/openpgp.worker.js' });
+    } catch (e) {
+      openpgp.util.print_debug_error(e);
+    }
   },
   beforeEach: function() {
     openpgp.config.use_native = true;
diff --git a/test/general/ecc_nist.js b/test/general/ecc_nist.js
index 533b6786..0fa53544 100644
--- a/test/general/ecc_nist.js
+++ b/test/general/ecc_nist.js
@@ -101,7 +101,11 @@ describe('Elliptic Curve Cryptography for NIST P-256,P-384,P-521 curves @lightwe
   tryTests('ECC Worker Tests', omnibus, {
     if: typeof window !== 'undefined' && window.Worker,
     before: async function() {
-      await openpgp.initWorker({ path:'../dist/openpgp.worker.js' });
+      try {
+        await openpgp.initWorker({ path:'../dist/openpgp.worker.js' });
+      } catch (e) {
+        openpgp.util.print_debug_error(e);
+      }
     },
     beforeEach: function() {
       openpgp.config.use_native = true;
diff --git a/test/general/key.js b/test/general/key.js
index 1f0368f8..12759c81 100644
--- a/test/general/key.js
+++ b/test/general/key.js
@@ -2005,7 +2005,7 @@ function versionSpecificTests() {
     openpgp.config.aead_mode = openpgp.enums.aead.experimental_gcm;
     if (openpgp.getWorker()) {
       openpgp.getWorker().workers.forEach(worker => {
-        worker.postMessage({ event: 'configure', config: openpgp.config });
+        openpgp.getWorker().callWorker(worker, 'configure', openpgp.config);
       });
     }
 
@@ -2041,7 +2041,7 @@ function versionSpecificTests() {
       openpgp.config.aead_mode = aead_modeVal;
       if (openpgp.getWorker()) {
         openpgp.getWorker().workers.forEach(worker => {
-          worker.postMessage({ event: 'configure', config: openpgp.config });
+          openpgp.getWorker().callWorker(worker, 'configure', openpgp.config);
         });
       }
     }
@@ -2545,7 +2545,11 @@ describe('Key', function() {
   tryTests('V4 - With Worker', versionSpecificTests, {
     if: typeof window !== 'undefined' && window.Worker,
     before: async function() {
-      await openpgp.initWorker({ path: '../dist/openpgp.worker.js' });
+      try {
+        await openpgp.initWorker({ path: '../dist/openpgp.worker.js' });
+      } catch (e) {
+        openpgp.util.print_debug_error(e);
+      }
     },
     after: function() {
       openpgp.destroyWorker();
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index 86a6aeed..52f0238f 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -516,7 +516,7 @@ describe('OpenPGP.js public api tests', function() {
         openpgp.initWorker({
           workers: [workerStub]
         }),
-        workerStub.onmessage({ data: { event: 'loaded' } })
+        workerStub.onmessage({ data: { id: 0, event: 'method-return' } })
       ]);
       expect(openpgp.getWorker()).to.exist;
       openpgp.destroyWorker();
@@ -671,7 +671,7 @@ describe('OpenPGP.js public api tests', function() {
         openpgp.initWorker({
           workers: [workerStub]
         }),
-        workerStub.onmessage({ data: { event: 'loaded' } })
+        workerStub.onmessage({ data: { id: 0, event: 'method-return' } })
       ]);
       const proxyGenStub = stub(openpgp.getWorker(), 'delegate');
       getWebCryptoAllStub.returns();
@@ -716,7 +716,11 @@ describe('OpenPGP.js public api tests', function() {
 
     it('should work in JS (with worker)', async function() {
       openpgp.config.use_native = false;
-      await openpgp.initWorker({ path:'../dist/openpgp.worker.js' });
+      try {
+        await openpgp.initWorker({ path:'../dist/openpgp.worker.js' });
+      } catch (e) {
+        openpgp.util.print_debug_error(e);
+      }
       const opt = {
         userIds: [{ name: 'Test User', email: 'text@example.com' }],
         numBits: 512
@@ -821,7 +825,11 @@ describe('OpenPGP.js public api tests', function() {
       const { workers } = openpgp.getWorker();
       try {
         await privateKey.keys[0].decrypt(passphrase)
-        await openpgp.initWorker({path: '../dist/openpgp.worker.js', workers, n: 2});
+        try {
+          await openpgp.initWorker({path: '../dist/openpgp.worker.js', workers, n: 2});
+        } catch (e) {
+          openpgp.util.print_debug_error(e);
+        }
 
         const workerTest = (_, index) => {
           const plaintext = input.createSomeMessage() + index;
@@ -842,7 +850,11 @@ describe('OpenPGP.js public api tests', function() {
         };
         await Promise.all(Array(10).fill(null).map(workerTest));
       } finally {
-        await openpgp.initWorker({path: '../dist/openpgp.worker.js', workers, n: 1 });
+        try {
+          await openpgp.initWorker({path: '../dist/openpgp.worker.js', workers, n: 1 });
+        } catch (e) {
+          openpgp.util.print_debug_error(e);
+        }
       }
     });
 
@@ -900,7 +912,11 @@ describe('OpenPGP.js public api tests', function() {
     tryTests('CFB mode (asm.js, worker)', tests, {
       if: typeof window !== 'undefined' && window.Worker,
       before: async function() {
-        await openpgp.initWorker({ path:'../dist/openpgp.worker.js' });
+        try {
+          await openpgp.initWorker({ path:'../dist/openpgp.worker.js' });
+        } catch (e) {
+          openpgp.util.print_debug_error(e);
+        }
       },
       beforeEach: function() {
         openpgp.config.aead_protect = false;
@@ -1641,7 +1657,7 @@ describe('OpenPGP.js public api tests', function() {
             openpgp.config.allow_unauthenticated_stream = !!allow_streaming;
             if (openpgp.getWorker()) {
               openpgp.getWorker().workers.forEach(worker => {
-                worker.postMessage({ event: 'configure', config: openpgp.config });
+                openpgp.getWorker().callWorker(worker, 'configure', openpgp.config);
               });
             }
             await Promise.all([badSumEncrypted, badBodyEncrypted].map(async (encrypted, i) => {
@@ -1847,7 +1863,7 @@ describe('OpenPGP.js public api tests', function() {
             openpgp.config.zero_copy = false;
             if (openpgp.getWorker()) {
               openpgp.getWorker().workers.forEach(worker => {
-                worker.postMessage({ event: 'configure', config: openpgp.config });
+                openpgp.getWorker().callWorker(worker, 'configure', openpgp.config);
               });
             }
             return openpgp.decrypt(decOpt);
diff --git a/test/general/signature.js b/test/general/signature.js
index 734b9eac..9ef6a71a 100644
--- a/test/general/signature.js
+++ b/test/general/signature.js
@@ -1334,7 +1334,11 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
   tryTests('With Worker', tests, {
     if: typeof window !== 'undefined' && window.Worker,
     before: async function() {
-      await openpgp.initWorker({ path: '../dist/openpgp.worker.js' });
+      try {
+        await openpgp.initWorker({ path:'../dist/openpgp.worker.js' });
+      } catch (e) {
+        openpgp.util.print_debug_error(e);
+      }
     },
     after: function() {
       openpgp.destroyWorker();
diff --git a/test/general/x25519.js b/test/general/x25519.js
index 670372ff..24fdadd3 100644
--- a/test/general/x25519.js
+++ b/test/general/x25519.js
@@ -545,7 +545,11 @@ tryTests('X25519 Omnibus Tests', omnibus, {
 tryTests('X25519 Omnibus Tests - Worker', omnibus, {
   if: typeof window !== 'undefined' && window.Worker,
   before: async function() {
-    await openpgp.initWorker({ path: '../dist/openpgp.worker.js' });
+    try {
+      await openpgp.initWorker({ path:'../dist/openpgp.worker.js' });
+    } catch (e) {
+      openpgp.util.print_debug_error(e);
+    }
   },
   beforeEach: function() {
     openpgp.config.use_native = true;
diff --git a/test/worker/async_proxy.js b/test/worker/async_proxy.js
index bedc9739..36990d9a 100644
--- a/test/worker/async_proxy.js
+++ b/test/worker/async_proxy.js
@@ -37,7 +37,11 @@ let pubKey;
 tryTests('Async Proxy', tests, {
   if: typeof window !== 'undefined' && window.Worker && window.MessageChannel,
   before: async function() {
-    await openpgp.initWorker({ path:'../dist/openpgp.worker.js' });
+    try {
+      await openpgp.initWorker({ path:'../dist/openpgp.worker.js' });
+    } catch (e) {
+      openpgp.util.print_debug_error(e);
+    }
     pubKey = (await openpgp.key.readArmored(pub_key)).keys[0];
   },
   after: async function() {
@@ -50,11 +54,14 @@ function tests() {
   describe('Random number pipeline', function() {
     it('Random number buffer automatically reseeded', async function() {
       const worker = new Worker('../dist/openpgp.worker.js');
-      const wProxy = new openpgp.AsyncProxy({ path:'../dist/openpgp.worker.js', workers: [worker] });
-      const loaded = await wProxy.loaded();
-      if (loaded) {
-        return wProxy.delegate('encrypt', { publicKeys:[pubKey], message:openpgp.message.fromText(plaintext) });
+      const wProxy = new openpgp.AsyncProxy();
+      try {
+        await wProxy.init({ path:'../dist/openpgp.worker.js', workers: [worker] });
+      } catch (e) {
+        openpgp.util.print_debug_error(e);
+        return;
       }
+      return wProxy.delegate('encrypt', { publicKeys:[pubKey], message:openpgp.message.fromText(plaintext) });
     });
   });