diff --git a/core/modules/big_pipe/src/EventSubscriber/HtmlResponseBigPipeSubscriber.php b/core/modules/big_pipe/src/EventSubscriber/HtmlResponseBigPipeSubscriber.php
index f8cef1077f10fa52a1866f7be24e507a547ab64f..0bccf0fa68507e5fd7ee7fdf9806f7fd092164b0 100644
--- a/core/modules/big_pipe/src/EventSubscriber/HtmlResponseBigPipeSubscriber.php
+++ b/core/modules/big_pipe/src/EventSubscriber/HtmlResponseBigPipeSubscriber.php
@@ -3,7 +3,7 @@
 namespace Drupal\big_pipe\EventSubscriber;
 
 use Drupal\Core\Render\HtmlResponse;
-use Drupal\big_pipe\Render\BigPipeInterface;
+use Drupal\big_pipe\Render\BigPipe;
 use Drupal\big_pipe\Render\BigPipeResponse;
 use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
 use Symfony\Component\HttpKernel\KernelEvents;
@@ -12,7 +12,7 @@
 /**
  * Response subscriber to replace the HtmlResponse with a BigPipeResponse.
  *
- * @see \Drupal\big_pipe\Render\BigPipeInterface
+ * @see \Drupal\big_pipe\Render\BigPipe
  *
  * @todo Refactor once https://www.drupal.org/node/2577631 lands.
  */
@@ -21,17 +21,17 @@ class HtmlResponseBigPipeSubscriber implements EventSubscriberInterface {
   /**
    * The BigPipe service.
    *
-   * @var \Drupal\big_pipe\Render\BigPipeInterface
+   * @var \Drupal\big_pipe\Render\BigPipe
    */
   protected $bigPipe;
 
   /**
    * Constructs a HtmlResponseBigPipeSubscriber object.
    *
-   * @param \Drupal\big_pipe\Render\BigPipeInterface $big_pipe
+   * @param \Drupal\big_pipe\Render\BigPipe $big_pipe
    *   The BigPipe service.
    */
-  public function __construct(BigPipeInterface $big_pipe) {
+  public function __construct(BigPipe $big_pipe) {
     $this->bigPipe = $big_pipe;
   }
 
@@ -102,8 +102,8 @@ public function onRespond(FilterResponseEvent $event) {
    * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
    *   A response event.
    *
-   * @return \Drupal\big_pipe\Render\BigPipeInterface
-   *   A BigPipe service.
+   * @return \Drupal\big_pipe\Render\BigPipe
+   *   The BigPipe service.
    */
   protected function getBigPipeService(FilterResponseEvent $event) {
     return $this->bigPipe;
diff --git a/core/modules/big_pipe/src/Render/BigPipe.php b/core/modules/big_pipe/src/Render/BigPipe.php
index 9337234337f031f66364cd8a87455f4e2dd88721..976d622e658826c25f25ce12eff39a39f3e29882 100644
--- a/core/modules/big_pipe/src/Render/BigPipe.php
+++ b/core/modules/big_pipe/src/Render/BigPipe.php
@@ -21,9 +21,133 @@
 use Symfony\Component\HttpKernel\KernelEvents;
 
 /**
- * The default BigPipe service.
+ * Service for sending an HTML response in chunks (to get faster page loads).
+ *
+ * At a high level, BigPipe sends a HTML response in chunks:
+ * 1. one chunk: everything until just before </body> — this contains BigPipe
+ *    placeholders for the personalized parts of the page. Hence this sends the
+ *    non-personalized parts of the page. Let's call it The Skeleton.
+ * 2. N chunks: a <script> tag per BigPipe placeholder in The Skeleton.
+ * 3. one chunk: </body> and everything after it.
+ *
+ * This is conceptually identical to Facebook's BigPipe (hence the name).
+ *
+ * @see https://www.facebook.com/notes/facebook-engineering/bigpipe-pipelining-web-pages-for-high-performance/389414033919
+ *
+ * The major way in which Drupal differs from Facebook's implementation (and
+ * others) is in its ability to automatically figure out which parts of the page
+ * can benefit from BigPipe-style delivery. Drupal's render system has the
+ * concept of "auto-placeholdering": content that is too dynamic is replaced
+ * with a placeholder that can then be rendered at a later time. On top of that,
+ * it also has the concept of "placeholder strategies": by default, placeholders
+ * are replaced on the server side and the response is blocked on all of them
+ * being replaced. But it's possible to add additional placeholder strategies.
+ * BigPipe is just another placeholder strategy. Others could be ESI, AJAX …
+ *
+ * @see https://www.drupal.org/developing/api/8/render/arrays/cacheability/auto-placeholdering
+ * @see \Drupal\Core\Render\PlaceholderGeneratorInterface::shouldAutomaticallyPlaceholder()
+ * @see \Drupal\Core\Render\Placeholder\PlaceholderStrategyInterface
+ * @see \Drupal\Core\Render\Placeholder\SingleFlushStrategy
+ * @see \Drupal\big_pipe\Render\Placeholder\BigPipeStrategy
+ *
+ * There is also one noteworthy technical addition that Drupal makes. BigPipe as
+ * described above, and as implemented by Facebook, can only work if JavaScript
+ * is enabled. The BigPipe module also makes it possible to replace placeholders
+ * using BigPipe in-situ, without JavaScript. This is not technically BigPipe at
+ * all; it's just the use of multiple flushes. Since it is able to reuse much of
+ * the logic though, we choose to call this "no-JS BigPipe".
+ *
+ * However, there is also a tangible benefit: some dynamic/expensive content is
+ * not HTML, but for example a HTML attribute value (or part thereof). It's not
+ * possible to efficiently replace such content using JavaScript, so "classic"
+ * BigPipe is out of the question. For example: CSRF tokens in URLs.
+ *
+ * This allows us to use both no-JS BigPipe and "classic" BigPipe in the same
+ * response to maximize the amount of content we can send as early as possible.
+ *
+ * Finally, a closer look at the implementation, and how it supports and reuses
+ * existing Drupal concepts:
+ * 1. BigPipe placeholders: 1 HtmlResponse + N embedded AjaxResponses.
+ *   - Before a BigPipe response is sent, it is just a HTML response that
+ *     contains BigPipe placeholders. Those placeholders look like
+ *     <div data-big-pipe-placeholder-id="…"></div>. JavaScript is used to
+ *     replace those placeholders.
+ *     Therefore these placeholders are actually sent to the client.
+ *   - The Skeleton of course has attachments, including most notably asset
+ *     libraries. And those we track in drupalSettings.ajaxPageState.libraries —
+ *     so that when we load new content through AJAX, we don't load the same
+ *     asset libraries again. A HTML page can have multiple AJAX responses, each
+ *     of which should take into account the combined AJAX page state of the
+ *     HTML document and all preceding AJAX responses.
+ *   - BigPipe does not make use of multiple AJAX requests/responses. It uses a
+ *     single HTML response. But it is a more long-lived one: The Skeleton is
+ *     sent first, the closing </body> tag is not yet sent, and the connection
+ *     is kept open. Whenever another BigPipe Placeholder is rendered, Drupal
+ *     sends (and so actually appends to the already-sent HTML) something like
+ *     <script type="application/vnd.drupal-ajax">[{"command":"settings","settings":{…}}, {"command":…}.
+ *   - So, for every BigPipe placeholder, we send such a <script
+ *     type="application/vnd.drupal-ajax"> tag. And the contents of that tag is
+ *     exactly like an AJAX response. The BigPipe module has JavaScript that
+ *     listens for these and applies them. Let's call it an Embedded AJAX
+ *     Response (since it is embedded in the HTML response). Now for the
+ *     interesting bit: each of those Embedded AJAX Responses must also take
+ *     into account the cumulative AJAX page state of the HTML document and all
+ *     preceding Embedded AJAX responses.
+ * 2. No-JS BigPipe placeholders: 1 HtmlResponse + N embedded HtmlResponses.
+ *   - Before a BigPipe response is sent, it is just a HTML response that
+ *     contains no-JS BigPipe placeholders. Those placeholders can take two
+ *     different forms:
+ *     1. <div data-big-pipe-nojs-placeholder-id="…"></div> if it's a
+ *        placeholder that will be replaced by HTML
+ *     2. big_pipe_nojs_placeholder_attribute_safe:… if it's a placeholder
+ *        inside a HTML attribute, in which 1. would be invalid (angle brackets
+ *        are not allowed inside HTML attributes)
+ *     No-JS BigPipe placeholders are not replaced using JavaScript, they must
+ *     be replaced upon sending the BigPipe response. So, while the response is
+ *     being sent, upon encountering these placeholders, their corresponding
+ *     placeholder replacements are sent instead.
+ *     Therefore these placeholders are never actually sent to the client.
+ *   - See second bullet of point 1.
+ *   - No-JS BigPipe does not use multiple AJAX requests/responses. It uses a
+ *     single HTML response. But it is a more long-lived one: The Skeleton is
+ *     split into multiple parts, the separators are where the no-JS BigPipe
+ *     placeholders used to be. Whenever another no-JS BigPipe placeholder is
+ *     rendered, Drupal sends (and so actually appends to the already-sent HTML)
+ *     something like
+ *     <link rel="stylesheet" …><script …><content>.
+ *   - So, for every no-JS BigPipe placeholder, we send its associated CSS and
+ *     header JS that has not already been sent (the bottom JS is not yet sent,
+ *     so we can accumulate all of it and send it together at the end). This
+ *     ensures that the markup is rendered as it was originally intended: its
+ *     CSS and JS used to be blocking, and it still is. Let's call it an
+ *     Embedded HTML response. Each of those Embedded HTML Responses must also
+ *     take into account the cumulative AJAX page state of the HTML document and
+ *     all preceding Embedded HTML responses.
+ *   - Finally: any non-critical JavaScript associated with all Embedded HTML
+ *     Responses, i.e. any footer/bottom/non-header JavaScript, is loaded after
+ *     The Skeleton.
+ *
+ * Combining all of the above, when using both BigPipe placeholders and no-JS
+ * BigPipe placeholders, we therefore send: 1 HtmlResponse + M Embedded HTML
+ * Responses + N Embedded AJAX Responses. Schematically, we send these chunks:
+ *  1. Byte zero until 1st no-JS placeholder: headers + <html><head /><div>…</div>
+ *  2. 1st no-JS placeholder replacement: <link rel="stylesheet" …><script …><content>
+ *  3. Content until 2nd no-JS placeholder: <div>…</div>
+ *  4. 2nd no-JS placeholder replacement: <link rel="stylesheet" …><script …><content>
+ *  5. Content until 3rd no-JS placeholder: <div>…</div>
+ *  6. [… repeat until all no-JS placeholder replacements are sent …]
+ *  7. Send content after last no-JS placeholder.
+ *  8. Send script_bottom (markup to load bottom i.e. non-critical JS).
+ *  9. 1st placeholder replacement: <script type="application/vnd.drupal-ajax">[{"command":"settings","settings":{…}}, {"command":…}
+ * 10. 2nd placeholder replacement: <script type="application/vnd.drupal-ajax">[{"command":"settings","settings":{…}}, {"command":…}
+ * 11. [… repeat until all placeholder replacements are sent …]
+ * 12. Send </body> and everything after it.
+ * 13. Terminate request/response cycle.
+ *
+ * @see \Drupal\big_pipe\EventSubscriber\HtmlResponseBigPipeSubscriber
+ * @see \Drupal\big_pipe\Render\Placeholder\BigPipeStrategy
  */
-class BigPipe implements BigPipeInterface {
+class BigPipe {
 
   /**
    * The BigPipe placeholder replacements start signal.
@@ -143,7 +267,15 @@ protected function sendChunk($chunk) {
   }
 
   /**
-   * {@inheritdoc}
+   * Sends an HTML response in chunks using the BigPipe technique.
+   *
+   * @param \Drupal\big_pipe\Render\BigPipeResponse $response
+   *   The BigPipe response to send.
+   *
+   * @internal
+   *   This method should only be invoked by
+   *   \Drupal\big_pipe\Render\BigPipeResponse, which is itself an internal
+   *   class.
    */
   public function sendContent(BigPipeResponse $response) {
     $content = $response->getContent();
diff --git a/core/modules/big_pipe/src/Render/BigPipeInterface.php b/core/modules/big_pipe/src/Render/BigPipeInterface.php
deleted file mode 100644
index 420b5db67ba55d65df2912829ca6d6516e4446c7..0000000000000000000000000000000000000000
--- a/core/modules/big_pipe/src/Render/BigPipeInterface.php
+++ /dev/null
@@ -1,147 +0,0 @@
-<?php
-
-namespace Drupal\big_pipe\Render;
-
-/**
- * Interface for sending an HTML response in chunks (to get faster page loads).
- *
- * At a high level, BigPipe sends a HTML response in chunks:
- * 1. one chunk: everything until just before </body> — this contains BigPipe
- *    placeholders for the personalized parts of the page. Hence this sends the
- *    non-personalized parts of the page. Let's call it The Skeleton.
- * 2. N chunks: a <script> tag per BigPipe placeholder in The Skeleton.
- * 3. one chunk: </body> and everything after it.
- *
- * This is conceptually identical to Facebook's BigPipe (hence the name).
- *
- * @see https://www.facebook.com/notes/facebook-engineering/bigpipe-pipelining-web-pages-for-high-performance/389414033919
- *
- * The major way in which Drupal differs from Facebook's implementation (and
- * others) is in its ability to automatically figure out which parts of the page
- * can benefit from BigPipe-style delivery. Drupal's render system has the
- * concept of "auto-placeholdering": content that is too dynamic is replaced
- * with a placeholder that can then be rendered at a later time. On top of that,
- * it also has the concept of "placeholder strategies": by default, placeholders
- * are replaced on the server side and the response is blocked on all of them
- * being replaced. But it's possible to add additional placeholder strategies.
- * BigPipe is just another placeholder strategy. Others could be ESI, AJAX …
- *
- * @see https://www.drupal.org/developing/api/8/render/arrays/cacheability/auto-placeholdering
- * @see \Drupal\Core\Render\PlaceholderGeneratorInterface::shouldAutomaticallyPlaceholder()
- * @see \Drupal\Core\Render\Placeholder\PlaceholderStrategyInterface
- * @see \Drupal\Core\Render\Placeholder\SingleFlushStrategy
- * @see \Drupal\big_pipe\Render\Placeholder\BigPipeStrategy
- *
- * There is also one noteworthy technical addition that Drupal makes. BigPipe as
- * described above, and as implemented by Facebook, can only work if JavaScript
- * is enabled. The BigPipe module also makes it possible to replace placeholders
- * using BigPipe in-situ, without JavaScript. This is not technically BigPipe at
- * all; it's just the use of multiple flushes. Since it is able to reuse much of
- * the logic though, we choose to call this "no-JS BigPipe".
- *
- * However, there is also a tangible benefit: some dynamic/expensive content is
- * not HTML, but for example a HTML attribute value (or part thereof). It's not
- * possible to efficiently replace such content using JavaScript, so "classic"
- * BigPipe is out of the question. For example: CSRF tokens in URLs.
- *
- * This allows us to use both no-JS BigPipe and "classic" BigPipe in the same
- * response to maximize the amount of content we can send as early as possible.
- *
- * Finally, a closer look at the implementation, and how it supports and reuses
- * existing Drupal concepts:
- * 1. BigPipe placeholders: 1 HtmlResponse + N embedded AjaxResponses.
- *   - Before a BigPipe response is sent, it is just a HTML response that
- *     contains BigPipe placeholders. Those placeholders look like
- *     <div data-big-pipe-placeholder-id="…"></div>. JavaScript is used to
- *     replace those placeholders.
- *     Therefore these placeholders are actually sent to the client.
- *   - The Skeleton of course has attachments, including most notably asset
- *     libraries. And those we track in drupalSettings.ajaxPageState.libraries —
- *     so that when we load new content through AJAX, we don't load the same
- *     asset libraries again. A HTML page can have multiple AJAX responses, each
- *     of which should take into account the combined AJAX page state of the
- *     HTML document and all preceding AJAX responses.
- *   - BigPipe does not make use of multiple AJAX requests/responses. It uses a
- *     single HTML response. But it is a more long-lived one: The Skeleton is
- *     sent first, the closing </body> tag is not yet sent, and the connection
- *     is kept open. Whenever another BigPipe Placeholder is rendered, Drupal
- *     sends (and so actually appends to the already-sent HTML) something like
- *     <script type="application/vnd.drupal-ajax">[{"command":"settings","settings":{…}}, {"command":…}.
- *   - So, for every BigPipe placeholder, we send such a <script
- *     type="application/vnd.drupal-ajax"> tag. And the contents of that tag is
- *     exactly like an AJAX response. The BigPipe module has JavaScript that
- *     listens for these and applies them. Let's call it an Embedded AJAX
- *     Response (since it is embedded in the HTML response). Now for the
- *     interesting bit: each of those Embedded AJAX Responses must also take
- *     into account the cumulative AJAX page state of the HTML document and all
- *     preceding Embedded AJAX responses.
- * 2. No-JS BigPipe placeholders: 1 HtmlResponse + N embedded HtmlResponses.
- *   - Before a BigPipe response is sent, it is just a HTML response that
- *     contains no-JS BigPipe placeholders. Those placeholders can take two
- *     different forms:
- *     1. <div data-big-pipe-nojs-placeholder-id="…"></div> if it's a
- *        placeholder that will be replaced by HTML
- *     2. big_pipe_nojs_placeholder_attribute_safe:… if it's a placeholder
- *        inside a HTML attribute, in which 1. would be invalid (angle brackets
- *        are not allowed inside HTML attributes)
- *     No-JS BigPipe placeholders are not replaced using JavaScript, they must
- *     be replaced upon sending the BigPipe response. So, while the response is
- *     being sent, upon encountering these placeholders, their corresponding
- *     placeholder replacements are sent instead.
- *     Therefore these placeholders are never actually sent to the client.
- *   - See second bullet of point 1.
- *   - No-JS BigPipe does not use multiple AJAX requests/responses. It uses a
- *     single HTML response. But it is a more long-lived one: The Skeleton is
- *     split into multiple parts, the separators are where the no-JS BigPipe
- *     placeholders used to be. Whenever another no-JS BigPipe placeholder is
- *     rendered, Drupal sends (and so actually appends to the already-sent HTML)
- *     something like
- *     <link rel="stylesheet" …><script …><content>.
- *   - So, for every no-JS BigPipe placeholder, we send its associated CSS and
- *     header JS that has not already been sent (the bottom JS is not yet sent,
- *     so we can accumulate all of it and send it together at the end). This
- *     ensures that the markup is rendered as it was originally intended: its
- *     CSS and JS used to be blocking, and it still is. Let's call it an
- *     Embedded HTML response. Each of those Embedded HTML Responses must also
- *     take into account the cumulative AJAX page state of the HTML document and
- *     all preceding Embedded HTML responses.
- *   - Finally: any non-critical JavaScript associated with all Embedded HTML
- *     Responses, i.e. any footer/bottom/non-header JavaScript, is loaded after
- *     The Skeleton.
- *
- * Combining all of the above, when using both BigPipe placeholders and no-JS
- * BigPipe placeholders, we therefore send: 1 HtmlResponse + M Embedded HTML
- * Responses + N Embedded AJAX Responses. Schematically, we send these chunks:
- *  1. Byte zero until 1st no-JS placeholder: headers + <html><head /><div>…</div>
- *  2. 1st no-JS placeholder replacement: <link rel="stylesheet" …><script …><content>
- *  3. Content until 2nd no-JS placeholder: <div>…</div>
- *  4. 2nd no-JS placeholder replacement: <link rel="stylesheet" …><script …><content>
- *  5. Content until 3rd no-JS placeholder: <div>…</div>
- *  6. [… repeat until all no-JS placeholder replacements are sent …]
- *  7. Send content after last no-JS placeholder.
- *  8. Send script_bottom (markup to load bottom i.e. non-critical JS).
- *  9. 1st placeholder replacement: <script type="application/vnd.drupal-ajax">[{"command":"settings","settings":{…}}, {"command":…}
- * 10. 2nd placeholder replacement: <script type="application/vnd.drupal-ajax">[{"command":"settings","settings":{…}}, {"command":…}
- * 11. [… repeat until all placeholder replacements are sent …]
- * 12. Send </body> and everything after it.
- * 13. Terminate request/response cycle.
- *
- * @see \Drupal\big_pipe\EventSubscriber\HtmlResponseBigPipeSubscriber
- * @see \Drupal\big_pipe\Render\Placeholder\BigPipeStrategy
- */
-interface BigPipeInterface {
-
-  /**
-   * Sends an HTML response in chunks using the BigPipe technique.
-   *
-   * @param \Drupal\big_pipe\Render\BigPipeResponse $response
-   *   The BigPipe response to send.
-   *
-   * @internal
-   *   This method should only be invoked by
-   *   \Drupal\big_pipe\Render\BigPipeResponse, which is itself an internal
-   *   class.
-   */
-  public function sendContent(BigPipeResponse $response);
-
-}
diff --git a/core/modules/big_pipe/src/Render/BigPipeResponse.php b/core/modules/big_pipe/src/Render/BigPipeResponse.php
index f74cec9a822216005848327f79fb0c6300eb7b47..70b637d34d8d6caa708be730a122cbabeae99da9 100644
--- a/core/modules/big_pipe/src/Render/BigPipeResponse.php
+++ b/core/modules/big_pipe/src/Render/BigPipeResponse.php
@@ -11,7 +11,7 @@
  * it makes the content inaccessible (hidden behind a callback), which means no
  * middlewares are able to modify the content anymore.
  *
- * @see \Drupal\big_pipe\Render\BigPipeInterface
+ * @see \Drupal\big_pipe\Render\BigPipe
  *
  * @internal
  *   This is a temporary solution until a generic response emitter interface is
@@ -23,7 +23,7 @@ class BigPipeResponse extends HtmlResponse {
   /**
    * The BigPipe service.
    *
-   * @var \Drupal\big_pipe\Render\BigPipeInterface
+   * @var \Drupal\big_pipe\Render\BigPipe
    */
   protected $bigPipe;
 
@@ -98,10 +98,10 @@ protected function populateBasedOnOriginalHtmlResponse() {
   /**
    * Sets the BigPipe service to use.
    *
-   * @param \Drupal\big_pipe\Render\BigPipeInterface $big_pipe
+   * @param \Drupal\big_pipe\Render\BigPipe $big_pipe
    *   The BigPipe service.
    */
-  public function setBigPipeService(BigPipeInterface $big_pipe) {
+  public function setBigPipeService(BigPipe $big_pipe) {
     $this->bigPipe = $big_pipe;
   }
 
diff --git a/core/modules/big_pipe/src/Render/BigPipeResponseAttachmentsProcessor.php b/core/modules/big_pipe/src/Render/BigPipeResponseAttachmentsProcessor.php
index 32640c2f7315971c7f8826bca8c8f5490c31fd66..94b8923700ddbd41a9a004bf68770cb279dd5641 100644
--- a/core/modules/big_pipe/src/Render/BigPipeResponseAttachmentsProcessor.php
+++ b/core/modules/big_pipe/src/Render/BigPipeResponseAttachmentsProcessor.php
@@ -17,7 +17,7 @@
  * Processes attachments of HTML responses with BigPipe enabled.
  *
  * @see \Drupal\Core\Render\HtmlResponseAttachmentsProcessor
- * @see \Drupal\big_pipe\Render\BigPipeInterface
+ * @see \Drupal\big_pipe\Render\BigPipe
  */
 class BigPipeResponseAttachmentsProcessor extends HtmlResponseAttachmentsProcessor {
 
diff --git a/core/modules/big_pipe/src/Render/Placeholder/BigPipeStrategy.php b/core/modules/big_pipe/src/Render/Placeholder/BigPipeStrategy.php
index 7af53f0f518d64c5096b3e0081a8cf1a69ba6a35..46a20c68da4cebd1075018dddaca42d3d39274a3 100644
--- a/core/modules/big_pipe/src/Render/Placeholder/BigPipeStrategy.php
+++ b/core/modules/big_pipe/src/Render/Placeholder/BigPipeStrategy.php
@@ -56,7 +56,7 @@
  * See \Drupal\big_pipe\Render\BigPipe for detailed documentation on how those
  * different placeholders are actually replaced.
  *
- * @see \Drupal\big_pipe\Render\BigPipeInterface
+ * @see \Drupal\big_pipe\Render\BigPipe
  */
 class BigPipeStrategy implements PlaceholderStrategyInterface {