Facebook Pixel CodeとGoogle Chrome75の相性が良くない件について

Google Chrome75 でフォームの alert や prompt が勝手に閉じてしまうというバグが報告されています。

https://bugs.chromium.org/p/chromium/issues/detail?id=972456

削除系の処理などだとフォームのボタンをクリックした際に confirm を表示して「OK」をクリックしたあとでsubmitが発動するケースもあるかと思いますが、それが正常に処理されなくなるという不具合です。

# この問題が発生するケース

* formのPOST時にconfirmを表示してからSubmitしている
* Facebook Pixel Codeを導入している（iframeでのPOSTが実行される）
* formのPOST時のQueryStringが2048文字以上である

Facebook Pixel Codeが原因で発生する件については以下でも言及されています。

https://bugs.chromium.org/p/chromium/issues/detail?id=972456#c10


# 理由


Facebook Pixel Codeのタグを見てみましょう。

https://connect.facebook.net/en_US/fbevents.js

```js
fbq('track', "PageView");
```

を設定しているとおそらくクリックイベントあたりを判定してFacebookにGETあるいはPOSTでデータを送っているようです。POSTであってもFacebookに送信する際にはGETで送っていることもあったのですが、



```js
                    c = function c() {
                        var f = this;
                        l(this, c);
                        this.sendGET = function(b, c, d) {
                            b.replaceEntry("rqm", "GET");
                            var g = b.toQueryString();
                            g = e(c, d) + "?" + g;
                            if (g.length < 2048) {
                                var h = new Image();
                                if (d != null) {
                                    var i = a.getShouldProxy();
                                    h.onerror = function() {
                                        a.setShouldProxy(!0),
                                        i || f.sendGET(b, c, d)
                                    }
                                }
                                h.src = g;
                                return !0
                            }
                            return !1
                        }
                        ;
                        this.sendPOST = function(a, c, d) {
                            var e = b.get("xhr_cors_post");
                            if (e) {
                                a.append("exp", e.code);
                                if (e.isInExperimentGroup)
                                    return f._sendXHRPost(a, c, d)
                            }
                            return f._sendFormPOST(a, c, d)
                        }
                        ;
```
にあるように、 toQueryString が 2048より短ければGETでリクエストが送信されます。

次にPOST時の動きを見てみます。iframeを作成してその中でPOSTをしています。


```js
                        this._sendFormPOST = function(c, i, j) {
                            c.replaceEntry("rqm", "formPOST");
                            var k = b.get("set_timeout_post");
                            k && c.append("exp", k.code);
                            var l = "fb" + Math.random().toString().replace(".", "")
                              , m = h.createElement("form");
                            m.method = "post";
                            m.action = e(i, j);
                            m.target = l;
                            m.acceptCharset = "utf-8";
                            m.style.display = "none";
                            var n = !!(g.attachEvent && !g.addEventListener)
                              , o = h.createElement("iframe");
                            n && (o.name = l);
                            o.src = "about:blank";
                            o.id = l;
                            o.name = l;
                            m.appendChild(o);
                            d(o, "load", function() {
                                c.each(function(a, b) {
                                    var c = h.createElement("input");
                                    c.name = decodeURIComponent(a);
                                    c.value = b;
                                    m.appendChild(c)
                                }),
                                d(o, "load", function() {
                                    m.parentNode && m.parentNode.removeChild(m)
                                }),
                                k && k.isInExperimentGroup && c.get("ev") === "SubscribedButtonClick" ? setTimeout(function() {
                                    return m.submit()
                                }) : m.submit()
                            });
```


https://bugs.chromium.org/p/chromium/issues/detail?id=972456#c35

で言及されているようにiframeにおけるPOST時の動作について次期バージョンでは修正がされているようです。

*2019/07/26追記*


# 解決策

setTimeoutを使ってconfirmの実行を遅延させます。つまり、**Facebook Pixel CodeのPOST処理を実行後に本来行いたいFORMのPOSTを実行する**ようにします。


https://bugs.chromium.org/p/chromium/issues/attachmentText?aid=401097

```
<html>
<head>
<script>
function submitAndAlert() {
  document.getElementById("form1").submit();
  alert("Form submitted");
}
function slowNavAndAlert() {
  frames[0].location.href = "http://tests.netsekure.org/slow.php?seconds=1";
  setTimeout(function () { alert("Started slow cross-process navigation in iframe"); }, 0);
}
</script>
</head>
<body>
<iframe name="frame1"></iframe>
<form id="form1" action="http://csreis.github.io" target="frame1">
</form>
Alert dismissal bug tests.  (Note: must reload the page after each button click.)<br>
<button onclick="submitAndAlert()">Submit form and alert (affects M75+)</button><br>
<button onclick="slowNavAndAlert()">Start slow navigation and alert (affects M67+)</button><br>
</body>
</html>
```

にあるように、

```
setTimeout(function () { alert("Started slow cross-process navigation in iframe"); }, 0);
```

を呼ぶことで回避することができます。Facebook Pixel CodeのPOST処理は100ms程度でレスポンスが返ってくるようですので、500msくらい待てばバッテイングすることなくダイアログの表示ができました。