# 暂停/完成的视频在YouTube上当向上滚动到足够加载新帖时会自动开始播放

**URL:** <https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692>\
**Category:** Bug\
**Created:** [2017年二月21日 00:05 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692 "2017-02-21T00:05:08Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![Aleksey\_Bogdanov](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/aleksey_bogdanov/32/288040_2.png) [@Aleksey\_Bogdanov](https://meta.discourse.org/u/Aleksey_Bogdanov)\
**Post date:** [2023年一月23日 09:52 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/39 "2023-01-23T09:52:10Z")

</div>

修补虚拟 DOM 来解决这个问题有什么不对或难的地方吗？

---

<div class="post-metadata">

**Author:** ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)\
**Post date:** [2023年一月23日 10:16 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/40 "2023-01-23T10:16:48Z")

</div>

欢迎提交 PR，我们尝试过但实在太难了

---

<div class="post-metadata">

**Author:** ![Aleksey\_Bogdanov](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/aleksey_bogdanov/32/288040_2.png) [@Aleksey\_Bogdanov](https://meta.discourse.org/u/Aleksey_Bogdanov)\
**Post date:** [2023年一月23日 13:58 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/41 "2023-01-23T13:58:47Z")

</div>

> <https://github.com/discourse/discourse/pull/19951>
>
> When a user pauses a youtube video and scrolls up high enough to load new posts,… the video either rewinds or restarts depending on the browser. The problem is solved by patching virtual-dom to handle element prepends without reordering old elements.

---

<div class="post-metadata">

**Author:** ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)\
**Post date:** [2023年一月23日 15:31 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/42 "2023-01-23T15:31:47Z")

</div>

很有意思！迁移到 vdom 的一个分支并非理想选择，但只要我们能证明没有回归（并且我们将其迁移到我们自己的 GitHub 组织），我们或许可以考虑。

您是否能够运行 vdom 测试套件来确认没有回归？为这种前置行为添加新的 vdom 测试会容易吗？

---

<div class="post-metadata">

**Author:** ![Aleksey\_Bogdanov](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/aleksey_bogdanov/32/288040_2.png) [@Aleksey\_Bogdanov](https://meta.discourse.org/u/Aleksey_Bogdanov)\
**Post date:** [2023年一月23日 18:21 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/43 "2023-01-23T18:21:43Z")

</div>

我将首先回答第二个问题。这种预置行为基本上是相同的，它只是消除了额外的工作。我将尝试说明 vdom 最初是如何工作的，以及修补后的工作方式。

假设有 20 篇帖子，滚动时会加载另外 10 篇。  
**最初** vdom 会进行以下一系列转换：  
[20 旧] → [20 旧, 10 新] // 10 个新元素被追加到末尾  
[20 旧, 10 新] → // 所有 30 个元素都被移除  
 → [10 新, 20 旧] // 所有 30 个元素都被插入到它们的位置  
**修补后** 序列变为：  
[20 旧] → [20 旧, 10 新] // 10 个新元素被追加到末尾  
[20 旧, 10 新] → [20 旧] // 10 个新元素从末尾移除  
[20 旧] → [10 新, 20 旧] // 10 个新元素被预置  
正如你所见，仍然存在额外的工作：原则上你可以立即预置这些元素，但这样我就可以在一个地方添加一些代码，而不必重写已经存在的内容。  
每次转换都成为一次 dom 操作，因此 YouTube 视频开始播放，因为最初旧元素被重新插入（这会触发它们被重新渲染），而在修补后它们会保持在原位。

---

<div class="post-metadata">

**Author:** ![Aleksey\_Bogdanov](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/aleksey_bogdanov/32/288040_2.png) [@Aleksey\_Bogdanov](https://meta.discourse.org/u/Aleksey_Bogdanov)\
**Post date:** [2023年一月24日 10:43 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/47 "2023-01-24T10:43:22Z")

</div>

这是 virtual-dom 的 package.json 的摘录

```json
"scripts": {
    "test": "node ./test/index.js | tap-spec",
    "dot": "node ./test/index.js | tap-dot",
    "start": "node ./index.js",
    "cover": "istanbul cover --report html --print detail ./test/index.js",
    "view-cover": "istanbul report html & opn ./coverage/index.html",
    "browser": "run-browser test/index.js",
    "phantom": "run-browser test/index.js -b | tap-spec",
    "dist": "browserify --standalone virtual-dom index.js > dist/virtual-dom.js",
    "travis-test": "npm run phantom && npm run cover && istanbul report lcov && ((cat coverage/lcov.info | coveralls) || exit 0)",
    "release": "npm run release-patch",
    "release-patch": "git checkout master && npm version patch && git push origin master --tags && npm publish",
    "release-minor": "git checkout master && npm version minor && git push origin master --tags && npm publish",
    "release-major": "git checkout master && npm version major && git push origin master --tags && npm publish"
  },

```

在这些脚本中，“test”、“dot”、“cover”、“view-cover”、“browser”、“phantom”、“travis-test”似乎与测试相关。  
“browser”、“phantom”、“travis-test”由于我代码中较新的 JavaScript 构造而导致解析错误。其他脚本则通过。如果我将此代码

```javascript
        var prepend = simulate.every(item => item && item.key)
        prepend &= aChildren.every((item, i) => item.key === bChildren[i + shift].key)

```

更改为此代码

```javascript
        var prepend = true
        for (var i = 0; prepend && i < simulate.length; i++) {
            prepend = simulate[i] && simulate[i].key
        }
        for (var i = 0; prepend && i < aChildren.length; i++) {
            prepend = aChildren[i].key === bChildren[i + shift].key
        }

```

那么所有脚本都能通过。如果希望满足所有这些脚本，我可以将此更改推送到以保持 JavaScript 的旧版本一致性。

---

<div class="post-metadata">

**Author:** ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)\
**Post date:** [2023年一月24日 11:03 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/48 "2023-01-24T11:03:50Z")

</div>

> [@Aleksey\_Bogdanov](#):
>
> 如果希望保留所有这些脚本，我可以推送此更改以保持javascript的一致性。

👍 请这样做——让我们保持他们现有的测试套件正常运行

我刚刚将 virtual-dom 分叉到 [GitHub - discourse/virtual-dom: A Virtual DOM and diffing algorithm](https://github.com/discourse/virtual-dom) - 请向该存储库提交一个 PR？

---

<div class="post-metadata">

**Author:** ![Aleksey\_Bogdanov](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/aleksey_bogdanov/32/288040_2.png) [@Aleksey\_Bogdanov](https://meta.discourse.org/u/Aleksey_Bogdanov)\
**Post date:** [2023年一月24日 12:28 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/49 "2023-01-24T12:28:47Z")

</div>

> <https://github.com/discourse/virtual-dom/pull/2>

---

<div class="post-metadata">

**Author:** ![Aleksey\_Bogdanov](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/aleksey_bogdanov/32/288040_2.png) [@Aleksey\_Bogdanov](https://meta.discourse.org/u/Aleksey_Bogdanov)\
**Post date:** [2023年一月25日 19:59 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/50 "2023-01-25T19:59:19Z")

</div>

我还应该指出，我对 virtual-dom 的更改非常有限。它专门针对 prepends，并在所有其他情况下回退到原始算法。而且，如果普遍看待这个问题，原始算法仍然不完美（不难举出一些例子，它会不必要地触及旧元素）。另一方面，它能很好地处理 appends、removes、single inserts。而且有了这个，你需要对 post stream 进行真正的优化才能突破。所以，实际上解决普遍问题可能有点矫枉过正，尽管当然，当你这样做时，你可以睡得更好。

---

<div class="post-metadata">

**Author:** ![Aleksey\_Bogdanov](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/aleksey_bogdanov/32/288040_2.png) [@Aleksey\_Bogdanov](https://meta.discourse.org/u/Aleksey_Bogdanov)\
**Post date:** [2023年二月4日 13:36 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/53 "2023-02-04T13:36:28Z")

</div>

我推送了一些新的测试。你打算近期审查一下这个 PR 吗？

---

<div class="post-metadata">

**Author:** ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)\
**Post date:** [2023年二月4日 14:19 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/54 "2023-02-04T14:19:00Z")

</div>

谢谢 Aleksey - 我将在下周内完成审阅

---

<div class="post-metadata">

**Author:** ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)\
**Post date:** [2023年二月6日 14:33 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/55 "2023-02-06T14:33:27Z")

</div>

我已经设置了 virtualdom 分支，并且可以确认它解决了手动测试中的 iframe 问题。

@Aleksey_Bogdanov 我想知道你是否能帮我处理一些事情。我一直在尝试在 Discourse 中添加一个测试。本质上：

1. 渲染 `<span>ElementOne</span><span>ElementTwo</span>`

2. 删除 ElementTwo，并预置 `PrependedElement`

3. 检查结果是否为 `<span>PrependedElement</span><span>ElementOne</span>`

4. 检查原始 ElementOne span 是否等于最终的 ElementOne span（即检查它没有被重新渲染）

不幸的是，（4）中的检查失败了，这意味着 ElementOne 被重新渲染了。你有什么想法为什么新的逻辑在这种情况下不起作用吗？🤔

我已经将新的分支配置和失败的测试推送到[现有的 PR](https://github.com/discourse/discourse/pull/19951)。

---

<div class="post-metadata">

**Author:** ![Aleksey\_Bogdanov](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/aleksey_bogdanov/32/288040_2.png) [@Aleksey\_Bogdanov](https://meta.discourse.org/u/Aleksey_Bogdanov)\
**Post date:** [2023年二月6日 15:56 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/56 "2023-02-06T15:56:08Z")

</div>

是的，我之前写过关于这个[问题](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/50?u=aleksey_bogdanov)。  
我不会期望这能普遍奏效（并且你描述的测试能通过）。最初，它适用于追加、删除、单个插入（也许是它们的某种组合）。通过我的更改，它也适用于纯粹的前置，这应该能解决 YouTube 的 bug。你的测试包含“删除 + 前置”。这不在我的更改范围内。  
一个更健壮的解决方案至少需要重写 virtual-dom 中的 ‘reorder’ 和 ‘diffChildren’。我可以尝试一下，但这引出了一个问题：你打算长期维护自己的 virtual-dom 分支吗？如果我们想做到健壮，尝试切换到一个类似的主动维护的库可能更好，并且花费的时间和精力更少。我猜其他库现在已经解决了这个问题。

---

<div class="post-metadata">

**Author:** ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)\
**Post date:** [2023年二月6日 16:38 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/57 "2023-02-06T16:38:08Z")

</div>

> [@Aleksey\_Bogdanov](#):
>
> 您的测试包含“移除 + 前插”。这不在我的更改范围内。

我明白了——这说得通。但是，即使我将其改为“纯前插”，我也会遇到同样的失败。在相关的 `reorder()` 函数中设置断点，可以看到它在 `bFree.length === bChildren.length` 检查时出错：

 ![Screenshot 2023-02-06 at 16.32.51](https://global.discourse-cdn.com/meta/original/4X/e/c/0/ec019b95ae3783e16f21e23fb16ea6e231fa2de1.png)

我已经将更新后的测试推送到分支了。

> [@Aleksey\_Bogdanov](#):
>
> 您是否计划长期维护自己的 virtual-dom 分支？如果我们想做到健壮，尝试切换到一个类似且积极维护的库可能会更好，并且需要更少的时间和精力。我猜其他库现在可能已经解决了这个问题。

这绝对只是一个短期解决方案。我们已经开始用 Ember/Glimmer 渲染替换我们对 vdom 的使用。我们的目标是在未来 12 个月内替换帖子流实现。Glimmer 可以正确处理这种“前插”。

所以，我很乐意合并一个“不完整但比以前更好”的更改。但是，如果这不涉及太多工作，我想了解为什么这个测试不起作用 🤔

---

<div class="post-metadata">

**Author:** ![Aleksey\_Bogdanov](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/aleksey_bogdanov/32/288040_2.png) [@Aleksey\_Bogdanov](https://meta.discourse.org/u/Aleksey_Bogdanov)\
**Post date:** [2023年二月6日 19:30 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/58 "2023-02-06T19:30:45Z")

</div>

> [@david](#):
>
> 但是，如果不太麻烦的话，我想知道为什么这个测试不起作用 🤔

当然。我还不确定，但我会尽快查看。

---

<div class="post-metadata">

**Author:** ![Aleksey\_Bogdanov](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/aleksey_bogdanov/32/288040_2.png) [@Aleksey\_Bogdanov](https://meta.discourse.org/u/Aleksey_Bogdanov)\
**Post date:** [2023年二月7日 17:17 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/59 "2023-02-07T17:17:33Z")

</div>

更新。  
我添加了密钥以使测试通过。密钥会提示 virtual-dom 哪些元素对应哪些元素。没有它们，virtual-dom 就会假设元素遵循与之前相同的顺序，并且无法弄清楚它正在处理前置操作。  
然后，我将单个前置更改为多个前置，因为 virtual-dom 已经涵盖了单个插入（单个前置是一种特殊情况），所以它们不应该有区别。  
以上更改是我目前已推送的内容。

但是现在多个前置操作没有区别，这令人惊讶。我最初关于问题所在以及我的补丁为何有效的理论可能存在缺陷。所以我还在努力弄清楚。  
我注意到，David，你在浏览器中调试了测试。设置起来困难吗？我很难为测试设置调试器，如果你能给我一些指导，我将不胜感激。

---

<div class="post-metadata">

**Author:** ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)\
**Post date:** [2023年二月7日 18:07 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/60 "2023-02-07T18:07:39Z")

</div>

[quote=“Aleksey Bogdanov, post:59, topic:57692, username:Aleksey\_Bogdanov”]  
我添加了用于测试通过的键。键提示虚拟 DOM 哪些元素对应哪些元素  
[/quote]啊，我明白了——谢谢！

> [@Aleksey\_Bogdanov](#):
>
> 我注意到，David，你在浏览器中调试了测试。设置起来难吗？我很难为测试设置调试器，如果你能给我一些指导，我将不胜感激。

你有一个可用的 Discourse 开发设置吗？如果有，请启动它，在浏览器中访问 `/tests`，然后使用顶部的过滤器 UI 搜索“avoids rerendering on prepend”。然后你可以使用浏览器开发者工具进行调试。（例如，转到 sources 选项卡，按 Ctrl+P 打开文件，搜索 `vdom/diff`，然后设置一个断点）

---

<div class="post-metadata">

**Author:** ![Aleksey\_Bogdanov](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/aleksey_bogdanov/32/288040_2.png) [@Aleksey\_Bogdanov](https://meta.discourse.org/u/Aleksey_Bogdanov)\
**Post date:** [2023年二月7日 18:16 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/61 "2023-02-07T18:16:54Z")

</div>

谢谢，我会试试的。

---

<div class="post-metadata">

**Author:** ![Aleksey\_Bogdanov](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/aleksey_bogdanov/32/288040_2.png) [@Aleksey\_Bogdanov](https://meta.discourse.org/u/Aleksey_Bogdanov)\
**Post date:** [2023年二月8日 15:13 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/62 "2023-02-08T15:13:09Z")

</div>

所以，这段代码

```javascript
assert.strictEqual(elementOneBefore, elementOneAfter);

```

没有区别，因为无论如何，elementOneBefore 在所有这些更改中都保持其身份。  
如果您想亲自看看，这里有一个小演示：

```xml
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Youtube Bug Demo</title>
</head>
<body>
    <script>
        let iframe = document.createElement("iframe");
        iframe.width = 690;
        iframe.height = 388;
        iframe.src = "https://www.youtube.com/embed/Xc5rB-0ZBcI";
        iframe.title = "Strange S.T.A.L.K.E.R. car glitch";
        document.body.appendChild(iframe);
        
        let button = document.createElement("button");
        button.type = "button";
        button.innerHTML = "Reinsert";
        button.onclick = function(){
            let iframeStart = document.querySelector("iframe");
            document.body.removeChild(iframeStart);
            document.body.insertBefore(iframeStart, button);
            let iframeEnd = document.querySelector("iframe");
            alert(iframeStart === iframeEnd);
        };
        document.body.appendChild(button);
    </script>
</body>
</html>

```

有区别的是那些 ‘removeChild’、‘insertBefore’ 调用，所以我添加了一个 DOM 变异检查。现在之前的版本测试失败，而当前版本测试通过，所以希望这足够了。

---

<div class="post-metadata">

**Author:** ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)\
**Post date:** [2023年二月9日 10:46 UTC](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692/63 "2023-02-09T10:46:38Z")

</div>

太好了，非常感谢 @Aleksey_Bogdanov 的工作。我刚刚合并了拉取请求，它将在未来一小时内在 Meta 上线。

[上一頁](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692.md?page=1)

[下一頁](https://meta.discourse.org/t/paused-finished-youtube-videos-automatically-start-playing-when-scrolling-up-far-enough-to-load-new-posts/57692.md?page=3)
