diff --git a/includes/cache.inc b/includes/cache.inc
new file mode 100644
index 0000000..3672d72
--- /dev/null
+++ b/includes/cache.inc
@@ -0,0 +1,160 @@
+<?php
+
+/**
+ * @file
+ * cache.inc
+ */
+
+/**
+ * Initializes the JS cache handler.
+ */
+function js_cache_initialize() {
+  global $conf;
+
+  // Collect all the explicitly configured cache bins.
+  $default_key = JsCache::DEFAULT_BIN_KEY;
+  $cache_bin_keys = array_values(array_filter(array_keys($conf), function ($key) {
+    return strpos($key, 'cache_class_') === 0;
+  }));
+  $cache_bin_keys[] = $default_key;
+
+  // Save the current configuration and override it to make sure an instance of
+  // our custom wrapper is instantiated for each configured bin.
+  $cache_conf = array();
+  $default_class = isset($conf[$default_key]) ? $conf[$default_key] : 'DrupalDatabaseCache';
+  foreach ($cache_bin_keys as $bin_key) {
+    $cache_conf[$bin_key] = isset($conf[$bin_key]) ? $conf[$bin_key] : $default_class;
+    $conf[$bin_key] = 'JsCache';
+  }
+
+  // Finally ensure our custom wrappers now which actual cache backend they are
+  // supposed to use.
+  JsCache::setConf($cache_conf);
+}
+
+
+/**
+ * JS custom cache handler.
+ *
+ * This ensures that Drupal is fully bootstrapped if an item cannot be retrieved
+ * from cache. By loading all hook implementations we avoid the risk of having
+ * corrupt cache entries stored during a callback execution.
+ */
+class JsCache implements DrupalCacheInterface {
+
+  const DEFAULT_BIN_KEY = 'cache_default_class';
+
+  /**
+   * The cache bin configuration.
+   *
+   * @var string[]
+   */
+  protected static $conf;
+
+  /**
+   * Flag indicating whether a full bootstrap can be performed.
+   *
+   * @var bool
+   */
+  protected static $fullBootstrap = FALSE;
+
+  /**
+   * The actual cache backend.
+   *
+   * @var DrupalCacheInterface
+   */
+  protected $backend;
+
+  /**
+   * Sets the cache bin configuration.
+   *
+   * @param string[] $conf
+   *   An associative array of cache backend class names keyed by their cache
+   *   bin name.
+   */
+  public static function setConf(array $conf) {
+    static::$conf = $conf;
+  }
+
+  /**
+   * Sets the flag indicating whether a full bootstrap can be performed.
+   *
+   * @param bool $full_bootstrap
+   *   The full bootstrap flag.
+   */
+  public static function setFullBootstrap($full_bootstrap) {
+    static::$fullBootstrap = $full_bootstrap;
+  }
+
+  /**
+   * Constructs a JS cache handler.
+   *
+   * @param string $bin
+   *   The cache bin name.
+   */
+  public function __construct($bin) {
+    if (isset(static::$conf[static::DEFAULT_BIN_KEY])) {
+      $class = isset(static::$conf[$bin]) ? static::$conf[$bin] : static::$conf[static::DEFAULT_BIN_KEY];
+      $this->backend = new $class($bin);
+    }
+    else {
+      throw new LogicException('The JS cache handler was not properly configured');
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get($cid) {
+    $cache = $this->backend->get($cid);
+    if (!$cache) {
+      $this->doFullBootstrap();
+    }
+    return $cache;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMultiple(&$cids) {
+    $cache = $this->backend->getMultiple($cids);
+    if ($cids) {
+      $this->doFullBootstrap();
+    }
+    return $cache;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function set($cid, $data, $expire = CACHE_PERMANENT) {
+    $this->backend->set($cid, $data, $expire);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function clear($cid = NULL, $wildcard = FALSE) {
+    $this->backend->clear($cid, $wildcard);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isEmpty() {
+    return $this->backend->isEmpty();
+  }
+
+  /**
+   * Fully bootstraps Drupal.
+   */
+  protected function doFullBootstrap() {
+    if (static::$fullBootstrap) {
+      static::setFullBootstrap(FALSE);
+      if (drupal_get_bootstrap_phase() < DRUPAL_BOOTSTRAP_FULL) {
+        js_bootstrap(DRUPAL_BOOTSTRAP_FULL);
+      }
+    }
+  }
+
+}
diff --git a/includes/callback.inc b/includes/callback.inc
index 1efdf00..a9e4b69 100644
--- a/includes/callback.inc
+++ b/includes/callback.inc
@@ -181,6 +181,12 @@ function js_callback_bootstrap(array &$info) {
         module_invoke($module, 'init');
       }
     }
+
+    // At this point in the execution flow it is safe to perform a full
+    // bootstrap in case of cache misses.
+    if (!empty($GLOBALS['conf']['js_cache'])) {
+      JsCache::setFullBootstrap(TRUE);
+    }
   }
 }
 
diff --git a/js.api.php b/js.api.php
index a4115bf..a531b58 100644
--- a/js.api.php
+++ b/js.api.php
@@ -57,7 +57,9 @@
  *     level to full, although this defeats the purpose of using this module.
  *     An alternative solution is monitoring the code paths triggered by the
  *     callback via the "xhprof" integration and make sure all required
- *     dependencies are actually loaded.
+ *     dependencies are actually loaded. Another viable solution is enabling the
+ *     JS custom cache handler by setting "$conf['js_cache'] = TRUE;" in your
+ *     php settings file. This will trigger a full bootstrap on cache misses.
  *   - includes: (optional) Load additional files from the /includes directory,
  *     without the extension.
  *   - dependencies: (optional) Load additional modules for this callback.
diff --git a/js.module b/js.module
index 739489b..4213c87 100644
--- a/js.module
+++ b/js.module
@@ -488,8 +488,14 @@ function js_execute_request() {
     register_shutdown_function('_js_fatal_error_handler');
   }
 
+  // Initialize the JS cache handler.
+  $memcache = !empty($conf['cache_default_class']) && $conf['cache_default_class'] === 'MemCacheDrupal';
+  if (!empty($conf['js_cache'])) {
+    module_load_include('inc', 'js', 'includes/cache');
+    js_cache_initialize();
+  }
   // Memcache requires an additional bootstrap phase to access variables.
-  if (!empty($conf['cache_default_class']) && $conf['cache_default_class'] === 'MemCacheDrupal') {
+  if ($memcache) {
     js_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES);
   }
 
