Javascript 数组状态将缓存在 iOS 12 Safari 中。这是错误还是功能?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/52390368/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 04:59:01  来源:igfitidea点击:

Array state will be cached in iOS 12 Safari. Is it a bug or feature?

javascriptiossafariios12

提问by abelyao

Update at 2018.10.31

This bug has been fixed in iOS 12.1, have a good day~

2018.10.31 更新

这个bug已经在iOS 12.1中修复了,祝你有个美好的一天~

I found a problem with Array's value state in the newly released iOS 12 Safari, for example, code like this:

我在新发布的iOS 12 Safari中发现Array的值状态有问题,比如代码是这样的:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <title>iOS 12 Safari bugs</title>
    <script type="text/javascript">
    window.addEventListener("load", function ()
    {
        let arr = [1, 2, 3, 4, 5];
        alert(arr.join());

        document.querySelector("button").addEventListener("click", function ()
        {
            arr.reverse();
        });
    });
    </script>
</head>
<body>
    <button>Array.reverse()</button>
    <p style="color:red;">test: click button and refresh page, code:</p>
</body>
</html>

After refreshing the page, the array's value is still reversed. Is this a bug or a feature of new Safari?

刷新页面后,数组的值仍然反转。这是新 Safari 的错误还是功能?



Here is a demo page. Try to use it with iOS 12 Safari: https://abelyao.github.io/others/ios12-safari-bug.html

这是一个演示页面。尝试在 iOS 12 Safari 中使用它:https: //abelyao.github.io/others/ios12-safari-bug.html

回答by hax

It's definitely a BUG! And it's a very serious bug.

绝对是BUG!这是一个非常严重的错误。

The bug is due to the optimization of array initializers in which all values are primitive literals. For example, given the function:

该错误是由于数组初始值设定项的优化,其中所有值都是原始文字。例如,给定函数:

function buildArray() {
    return [1, null, 'x'];
}

All returned array references from calls to buildArray()will link to the same memory, and some methods such as toString()will have their results cached. Normally, to preserve consistency, any mutable operation on such optimized arrays will copy the data to a separate memory space and link to it; this pattern is called copy-on-write, or CoW for short.

从调用返回的所有数组引用buildArray()都将链接到相同的内存,并且某些方法(例如)toString()会将其结果缓存。通常,为了保持一致性,对此类优化数组的任何可变操作都会将数据复制到单独的内存空间并链接到它;这种模式称为写时复制,简称 CoW。

The reverse()method mutates the array, so it should trigger a copy-on-write. But it doesn't, because the original implementor (Keith Miller of Apple) missed the reverse()case, even though he had written many testcases.

reverse()方法会改变数组,因此它应该触发写入时复制。但事实并非如此,因为最初的实现者(Apple 的 Keith Miller)错过了这个reverse()案例,尽管他已经编写了很多测试用例。

This bug was reported to Appleon August 21. The fix landed in the WebKit repositoryon August 27 and shipped in Safari 12.0.1 and iOS 12.1 on October 30, 2018.

此错误已于8 月 21 日报告给 Apple。该修复程序于 8 月 27 日登陆 WebKit 存储库,并于 2018 年 10 月 30 日在 Safari 12.0.1 和 iOS 12.1 中发布。

回答by Edire Fan

I wrote a lib to fix the bug. https://www.npmjs.com/package/array-reverse-polyfill

我写了一个库来修复这个错误。 https://www.npmjs.com/package/array-reverse-polyfill

This is the code:

这是代码

(function() {
  function buggy() {
    var a = [1, 2];
    return String(a) === String(a.reverse());
  }
  if(!buggy()) return;
  var r = Array.prototype.reverse;
  Array.prototype.reverse = function reverse() {
    if (Array.isArray(this)) this.length = this.length;
    return r.call(this);
  }
})();

回答by jsist

This is a bug in webkit. Though this has been solved at their end but not yet shipped with iOS GM release. One of the solutions to this problem:

这是webkit 中的一个错误。虽然这已经在他们的最后解决了,但还没有随 iOS GM 版本一起发布。此问题的解决方案之一:

(function() {
  function getReverseStr() {
    return [1, 2].reverse();
  }

  var n1 = getReverseStr()[0];
  var n2 = getReverseStr()[0];
  // check if there is an issue
  if(n1 != n2) {
    var origReverseFunction = Array.prototype.reverse;
    Array.prototype.reverse = function() {
      var newArr = this.slice();
      // use original reverse function so that edge cases are taken care of
      origReverseFunction.apply(newArr, arguments);
      var that = this;
      // copy reversed array
      newArr.forEach(function(value, index) {
        that[index] = value;
      });
      return this;
    }
  }
})();

回答by Atsushi Sasaki

It seems not to be cached if the number of elements changes.
I was able to avoid this like this.

如果元素数量发生变化,它似乎不会被缓存。
我能够像这样避免这种情况。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <title>iOS 12 Safari bugs</title>
    <script type="text/javascript">
    window.addEventListener("load", function ()
    {
        let arr = [1, 2, 3, 4, 5];
        arr.push('');
        arr.pop();
        alert(arr.join());

        document.querySelector("button").addEventListener("click", function ()
        {
            arr.reverse();
        });
    });
    </script>
</head>
<body>
    <button>Array.reverse()</button>
    <p style="color:red;">test: click button and refresh page, code:</p>
</body>
</html>