diff --git a/core/includes/common.inc b/core/includes/common.inc
index a08cafc1201cd3ff01723b50f94bc1a74cc2bdf9..4a8b1f0081a0950ed5036f6c249ae7c5d776ae79 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -3967,6 +3967,8 @@ function drupal_region_class($region) {
  *       which drupal_add_js() happened earlier in the page request.
  *   - defer: If set to TRUE, the defer attribute is set on the <script>
  *     tag. Defaults to FALSE.
+ *   - async: If set to TRUE, the async attribute is set on the <script>
+ *     tag. Defaults to FALSE.
  *   - cache: If set to FALSE, the JavaScript file is loaded anew on every page
  *     call; in other words, it is not cached. Used only when 'type' references
  *     a JavaScript file. Defaults to TRUE.
@@ -4039,6 +4041,7 @@ function drupal_add_js($data = NULL, $options = NULL) {
           'preprocess' => TRUE,
           'cache' => TRUE,
           'defer' => FALSE,
+          'async' => FALSE,
           'browsers' => array(),
         ),
       );
@@ -4086,6 +4089,7 @@ function drupal_js_defaults($data = NULL) {
     'scope' => 'header',
     'cache' => TRUE,
     'defer' => FALSE,
+    'async' => FALSE,
     'preprocess' => TRUE,
     'version' => NULL,
     'data' => $data,
@@ -4280,9 +4284,16 @@ function drupal_pre_render_scripts($elements) {
             break;
         }
 
-        // The defer attribute must not be specified if src is not defined.
-        if (!empty($item['defer']) && isset($element['#attributes']['src'])) {
-          $element['#attributes']['defer'] = 'defer';
+        // The defer and async attributes must not be specified if the src
+        // attribute is not present.
+        if (!empty($element['#attributes']['src'])) {
+          // Both may be specified for legacy browser fallback purposes.
+          if (!empty($item['async'])) {
+            $element['#attributes']['async'] = 'async';
+          }
+          if (!empty($item['defer'])) {
+            $element['#attributes']['defer'] = 'defer';
+          }
         }
 
         $elements[] = $element;
diff --git a/core/modules/system/tests/common.test b/core/modules/system/tests/common.test
index b50daad66006399f762844f831b3c047d28190e5..15286b6b880695451b459ecee5f0ce5e61173e5e 100644
--- a/core/modules/system/tests/common.test
+++ b/core/modules/system/tests/common.test
@@ -1180,6 +1180,40 @@ class CommonJavaScriptTestCase extends WebTestBase {
     $this->assertTrue(array_key_exists('http://example.com/script.js', $javascript), t('Added an external JavaScript file.'));
   }
 
+  /**
+   * Tests adding external JavaScript Files with the async attribute.
+   */
+  function testAsyncAttribute() {
+    $default_query_string = variable_get('css_js_query_string', '0');
+
+    drupal_add_js('http://example.com/script.js', array('async' => TRUE));
+    drupal_add_js('core/misc/collapse.js', array('async' => TRUE));
+    $javascript = drupal_get_js();
+
+    $expected_1 = '<script type="text/javascript" src="http://example.com/script.js?' . $default_query_string . '" async="async"></script>';
+    $expected_2 = '<script type="text/javascript" src="' . file_create_url('core/misc/collapse.js') . '?' . $default_query_string . '" async="async"></script>';
+
+    $this->assertTrue(strpos($javascript, $expected_1) > 0, t('Rendered external JavaScript with correct async attribute.'));
+    $this->assertTrue(strpos($javascript, $expected_2) > 0, t('Rendered internal JavaScript with correct async attribute.'));
+  }
+
+  /**
+   * Tests adding external JavaScript Files with the defer attribute.
+   */
+  function testDeferAttribute() {
+    $default_query_string = variable_get('css_js_query_string', '0');
+
+    drupal_add_js('http://example.com/script.js', array('defer' => TRUE));
+    drupal_add_js('core/misc/collapse.js', array('defer' => TRUE));
+    $javascript = drupal_get_js();
+
+    $expected_1 = '<script type="text/javascript" src="http://example.com/script.js?' . $default_query_string . '" defer="defer"></script>';
+    $expected_2 = '<script type="text/javascript" src="' . file_create_url('core/misc/collapse.js') . '?' . $default_query_string . '" defer="defer"></script>';
+
+    $this->assertTrue(strpos($javascript, $expected_1) > 0, t('Rendered external JavaScript with correct defer attribute.'));
+    $this->assertTrue(strpos($javascript, $expected_2) > 0, t('Rendered internal JavaScript with correct defer attribute.'));
+  }
+
   /**
    * Test drupal_get_js() for JavaScript settings.
    */