Javascript: Warum hat Safari Probleme mit const?
j.j.
- javascript
0 Auge- browser
- javascript
0 j.j.
0 Rolf B0 Rolf B
Hallo!
Nach über 20 Jahren schau ich hier mal wieder rein.
Fast ein Jahr lief ein kleiner Internetauftritt problemlos, bis ich auf die idee gekommen bin, in der Scriptdatei einige var
durch const
zu ersetzen. Getestet mit Chromium und Firefox, alles ok.
Es hat acht Wochen gedauert, bis aufgefallen ist, daß in Safari das komplette Script ignoriert wird (Grundfunktionen brauchen nur CSS). Ich hab keinen Mac und kein Iphone und prüfe Safari lediglich mit online-Scrennshots, was Zeitaufwendig ist und ich wegen der Banalität der Änderung wohl für überflüssig gehalten habe (jajahaha...).
Frage: Kennt jemand das Problem? Bei meinen Recherchen bin ich auf einige Ergebnisse gekommen, aber nicht schlauer geworden.
Das Schript ist hier: peter-hindelang.de/Bilder/script.js
Wenn man von den ersten sechs var
eine oder mehrere durch const
ersetzt, steigt Safari aus.
Es ist mir nicht gelungen, das Problem durch Versuch und Irrtum einzugrenzen. Die Welt wird auch mit var
nicht untergehen.
Hallo
Fast ein Jahr lief ein kleiner Internetauftritt problemlos, bis ich auf die idee gekommen bin, in der Scriptdatei einige
var
durchconst
zu ersetzen. Getestet mit Chromium und Firefox, alles ok.Es hat acht Wochen gedauert, bis aufgefallen ist, daß in Safari das komplette Script ignoriert wird (Grundfunktionen brauchen nur CSS).
Um welche Version des Safari geht es denn? Laut Can I use? unterstützt Safari sowohl in OS-X/MacOS als auch in iOS das Schlüsselwort const
in JS seit Version 11.
Leider kann ich nichts testen, aber du hast ja dein gesamtes Skript in einen Try-Catch-Block eingeschlossen. Gibt das catch(e)
irgendwas aus?
Tschö, Auge
Um welche Version des Safari geht es denn? Laut Can I use? unterstützt Safari sowohl in OS-X/MacOS als auch in iOS das Schlüsselwort
const
in JS seit Version 11.
Es geht auf jeden Fall um Safari 14, 15, 16, wahrscheinlich auch 17 (habs vergessen).
Leider kann ich nichts testen, aber du hast ja dein gesamtes Skript in einen Try-Catch-Block eingeschlossen. Gibt das
catch(e)
irgendwas aus?
Der catch-Block ist gedacht als Notbremse wenn es ganz schief läuft und für IE, Presto-Opera (Opera Mini) u.s.w. Wenn Safari den catch-Block erreicht hätte, wäre das Layout im Eimer. Das war nicht der Fall, die Seite hat ja großenteils funktioniert, was Teil des Problems war.
Danke! j.j.
Hallo j.j.,
steigt Safari aus.
Definiere das genauer.
Und bringe im catch e.toString() zur Anzeige.
Das muss etwas sein, was mit const eigentlich nichts zu tun hat.
Rolf
Hallo j.j.,
steigt Safari aus.
Definiere das genauer.
Und bringe im catch e.toString() zur Anzeige.
Das muss etwas sein, was mit const eigentlich nichts zu tun hat.
Rolf
Ich zitiere mich mal selber:
Ich hab keinen Mac und kein Iphone und prüfe Safari lediglich mit online-Scrennshots
j.j.
Hallo
… bringe im catch e.toString() zur Anzeige.
Das muss etwas sein, was mit const eigentlich nichts zu tun hat.
Rolf
Ich zitiere mich mal selber:
Ich hab keinen Mac und kein Iphone und prüfe Safari lediglich mit online-Scrennshots
Ja, aber …
Wie in meinem anderen Posting schon gesagt, kann der Safari das (const
) seit Ewigkeiten. Da muss etwas anderes im Spiel sein – wie Rolf schon anmerkte – und das sollte auch in anderen Browsern zu (einer) Fehlermeldung(en) führen.
Tschö, Auge
Wie in meinem anderen Posting schon gesagt, kann der Safari das (
const
) seit Ewigkeiten.
Ja, deshalb diese Frage.
Da muss etwas anderes im Spiel sein – wie Rolf schon anmerkte – und das sollte auch in anderen Browsern zu (einer) Fehlermeldung(en) führen.
Es gibt keine Fehlermeldung in anderen Browsern. Diese und auch Safari erreichen den catch-Block nicht.
Aber breaking news: Ich habe eine Testseite aufgesetzt mit einem Testscript und per Screenshot (Safari 15.4) scheint es zu funktionieren, warum auch immer. Ich hatte zwischenzeitlich kleinere (?) Änderungen gemacht.
Also, kann bitte jemand mit Safari mal testen? Es soll z.B. ein weißes Feld mit Titel und Größe des Bildes sichtbar werden und die gelben <input>
s bei mouseover reagieren. Die Bilder sollen beim draufklicken in die Mitte drehen.
Testseite: peter-hindelang.de/Bilder/test3.html
Testscript mit const
: https://peter-hindelang.de/Bilder/safari.js
Danke!
j.j.
P.S. Fällt mir grad wieder ein: Bei meinen Recherchen war irgendwas mit Safari const
block-scoping-Problemen, wenn man optionale {Klammern} wegläßt in speziellen Situationen oder so ähnlich. Das hab ich nicht auf mich bezogen, außerdem war es recht alt.
Testscript mitconst
:https://peter-hindelang.de/Bilder/safari.js
sorry, richtig ist: peter-hindelang.de/Bilder/safari-test.js
@@j.j.
Testseite:
peter-hindelang.de/Bilder/test3.html
Testscript mitconst
:https://peter-hindelang.de/Bilder/safari.js
sorry, richtig ist:
peter-hindelang.de/Bilder/safari-test.js
Nein. Richtig ist: https://peter-hindelang.de/Bilder/safari-test.js
Testseite: https://peter-hindelang.de/Bilder/test3.html
Wenn du willst, dass sich jemand dein Zeugs ansieht, verlinke es.
Kwakoni Yiquan
@@Gunnar Bittersmann
Testseite: https://peter-hindelang.de/Bilder/test3.html
Safari meldet in der Konsole:
Kwakoni Yiquan
Hallo Gunnar,
Der zweite Unterschied zwischen var und const ist das Hoisting, das bei const nicht stattfindet.
Von der Programmstruktur her scheint mir das hier unproblematisch.
Ich verstehe nicht, warum er keine Closure bildet und BL darin einschließt.
Rolf
Hallo
Der zweite Unterschied zwischen var und const ist das Hoisting, da bei const nicht stattfindet.
Von der Programmstruktur her scheint mir das hier unproblematisch.
Ich verstehe nicht, warum er keine Closure bildet und BL darin einschließt.
Vielleicht, weil die Struktur des HTML-Quelltexts der von Gunnar verlinkten Beispielseite kaputt ist. Es fehlt der Head-Bereich des Dokuments (<head></head>
) und <body</body>
. Alle Angaben, die im Head-Bereich stehen (meta
, title
und so) als auch der Content des Dokuments stehen direkt unter html
. Damit muss schon irgendwas mit document.body…
scheitern.
[edit]: Der von Gunnar genannte Fehler in Zeile 47 (das Fehlen der Variable BL
) ist wohl nur ein Folgefehler aus diesem Code.
const Knödel = document.body.querySelectorAll("input");
const Haupt = document.body.querySelector("main");
const Bild = Haupt.querySelectorAll("img");
const BL = Bild.length;
Wenn document.body
nicht tut, bleibt der Rest weg.
Tschö, Auge
Vielleicht, weil die Struktur des HTML-Quelltexts der von Gunnar verlinkten Beispielseite kaputt ist. Es fehlt der Head-Bereich des Dokuments (
<head></head>
) und<body</body>
. Alle Angaben, die im Head-Bereich stehen (meta
,title
und so) als auch der Content des Dokuments stehen direkt unterhtml
. Damit muss schon irgendwas mitdocument.body…
scheitern.Tschö, Auge
Hallo!
Dann wäre Safari aber nicht standardkonform, <html>
, <head>
, <body>
sind implizt. Auch Safari hat seit ewig den genormten HTML-Parser implementiert (und auch KHTML und alle andern Engines haben das seit Angeginn der Zeit so gehandhabt).
j.j.
Hallo
Vielleicht, weil die Struktur des HTML-Quelltexts der von Gunnar verlinkten Beispielseite kaputt ist. Es fehlt der Head-Bereich des Dokuments (
<head></head>
) und<body</body>
. Alle Angaben, die im Head-Bereich stehen (meta
,title
und so) als auch der Content des Dokuments stehen direkt unterhtml
. Damit muss schon irgendwas mitdocument.body…
scheitern.Dann wäre Safari aber nicht standardkonform,
<html>
,<head>
,<body>
sind implizt. Auch Safari hat seit ewig den genormten HTML-Parser implementiert (und auch KHTML und alle andern Engines haben das seit Angeginn der Zeit so gehandhabt).
An der Stelle lautet die Frage wohl eher, ob die JS-Engine das auch so sieht. Ich kann sie nicht beantworten, aber die von Gunnar per Screenshot gezeigte Fehlermeldung lässt mich daran zweifeln. Laut der Meldung in der Konsole ist die Variable BL
schlicht nicht auffindbar.
So, wie ich das sehe, läuft da folgendes ab.
// kein <body> => Haupt = null
const Haupt = document.body.querySelector("main");
// Haupt === null => Bild = null
const Bild = Haupt.querySelectorAll("img");
// Bild === null => BL = null
const BL = Bild.length;
Ob ich das wirklich richtig sehe, kann ich so zwischen Tür und Angel sowie ohne Safari aber nicht beurteilen.
Tschö, Auge
Moin,
So, wie ich das sehe, läuft da folgendes ab.
// kein <body> => Haupt = null const Haupt = document.body.querySelector("main"); // Haupt === null => Bild = null const Bild = Haupt.querySelectorAll("img"); // Bild === null => BL = null const BL = Bild.length;
Ob ich das wirklich richtig sehe, kann ich so zwischen Tür und Angel sowie ohne Safari aber nicht beurteilen.
müsste nicht schon beim Initialisieren von Bild
eine Null-Pointer-Exception geworfen werden, weil Haupt
null
ist und dementsprechend null.querySelectorAll(…)
nicht aufgerufen werden kann?
Viele Grüße
Robert
Hallo
So, wie ich das sehe, läuft da folgendes ab.
// kein <body> => Haupt = null const Haupt = document.body.querySelector("main"); // Haupt === null => Bild = null const Bild = Haupt.querySelectorAll("img"); // Bild === null => BL = null const BL = Bild.length;
Ob ich das wirklich richtig sehe, kann ich so zwischen Tür und Angel sowie ohne Safari aber nicht beurteilen.
müsste nicht schon beim Initialisieren von
Bild
eine Null-Pointer-Exception geworfen werden, weilHaupt
null
ist und dementsprechendnull.querySelectorAll(…)
nicht aufgerufen werden kann?
Ich stochere hier nur, da ich den Fehler im Firefox unter Windows nicht reproduzieren kann. Der von Gunnar gezeigte Fehler tritt nicht schon bei der Initialisierung und „Befüllung“ der Variable auf, sondern erst bei der Verwendung von BL
(zu dem zeitpunkt in Zeile 47).
Heute vormittag, als ich mir den Code angeschaut habe, stand dort noch …
for(var Arr = [], i = 0; i < BL; i++)
Arr.push(+ Bild[i].getAttribute("width"));
… später hat j.j. den Code durch …
for(var Arr = [], i = 0; i < Bild.length; i++)
Arr.push(+ Bild[i].getAttribute("width"));
… ersetzt, was offensichtlich auch nichts gebracht hat. Aber das sind, wie schon gesagt, meinerseits nur Mutmaßungen.
Tschö, Auge
Hallo Auge!
An der Stelle lautet die Frage wohl eher, ob die JS-Engine das auch so sieht.
Der HTML-Parser ist meineswissens tatsächlich in allen Browserengines exakt der aus der HTML-Norm. Er konstruiert das DOM (das ist der Elementbaum, den Du in den Entwicklerwerkzeugen der Browser siehst). Der Browser (also auch die JS-Engine) verwendet das DOM und nicht den Quelltext.
Ein paar Links:
Und grundsätzlich lesenswert: Simon Pieters, Idiosyncrasies of the HTML parser htmlparser.info/syntax/#optional-tags (seh Dir mal den Quelltext an ...)
(Neu war für mich übrigens die Info in Selfhtml, daß der Google HTML/CSS Style Guide das weglassen empfiehlt)
j.j.
@@Gunnar Bittersmann
Testseite: https://peter-hindelang.de/Bilder/test3.html
Safari meldet in der Konsole:
Danke! Ich hab BL
in Zeile 49 mal ersetzt mit Bild.length
. Der Fehler dürfte einfach weitergewandert sein zum nächsten Problem.
Welche Version hast Du?
j.j.
@@j.j.
Welche Version hast Du?
17.2.1.
Ich hab’s auf dem Mac getestet, nicht auf gekoppeltem iPhone.
Kwakoni Yiquan
Aber breaking news: Ich habe eine Testseite aufgesetzt mit einem Testscript und per Screenshot (Safari 15.4) scheint es zu funktionieren, warum auch immer. Ich hatte zwischenzeitlich kleinere (?) Änderungen gemacht.
Pahhh... zu früh gefreut! Funktioniert NICHT, und jetzt zeigt der Screenschor, daß Safari den catch-Block erreicht hat (Layout geändert, "Ihr alter Browser tut’s hier nicht mehr richtig!"). Das war bei meinen letzten Tests vor drei Wochen anders.
Also, kann bitte jemand mit Safari mal testen? Es soll z.B. ein weißes Feld mit Titel und Größe des Bildes sichtbar werden und die gelben
<input>
s bei mouseover reagieren. Die Bilder sollen beim draufklicken in die Mitte drehen.Testseite:
peter-hindelang.de/Bilder/test3.html
Testscript mitconst
:https://peter-hindelang.de/Bilder/safari.js
Testscript richtig: peter-hindelang.de/Bilder/safari-test.js
Danke!
j.j.
Hallo j.j.,
nochmal von vorn.
Du bindest das Script mit defer ein - okay. Damit gibt's keine Probleme mit einer Race Condition.
Dein gesamter Code hat diesen Grundaufbau:
try
{
const xy;
function trans()
{
// use xy -> Reference Error
}
(onresize=function() {
...
trans()
})();
}
catch (e) {
}
Dieser Code enthält einige Gemeinheiten, und bei Gunnar gab's ja auch schon im Desktop-Safari einen Error.
Die Zuweisung an onresize registriert einen Eventhandler für das Resize-Event auf dem window-Objekt. Im gleichen Zuge rufst Du ihn auch gleich das erste Mal auf. Danach wird er bei jedem Resize des Fensters erneut aufgerufen.
Der große Unterschied zwischen const und var ist hier: var wird im globalen Scope definiert (weil var keine Blockscopes beachtet). const wird hingegegen im Blockscope des try/catch definiert. Sobald der try-Block durch ist, endet der Scope, in dem xy definiert wird und xy ist ein Kandidat für den Garbage Collector.
Der es aber leben lassen sollte, denn:
Es ist MÖGLICH, dass diese Referenzbeziehungen, die xy (also dein BL) am Leben erhalten sollten, von Safari nicht korrekt beachtet werden. Ich habe das gerade in Chrome/Android betrachtet, da wird es korrekt erhalten. Safari kann ich nicht testen. Kann es sein, dass die JavaScript-Engine von Safari Closures nur auf Funktionsscope-Ebene bildet?
Zum Error-Handling: Wenn der Browser (Safari oder sonst einer) den resize-Handler aufruft, dann ist der globale try/catch-Block nicht mehr gültig. Die Handler-Funktion wurde zwar darin definiert, aber der Exception-Kontext gilt nur beim ersten Script-Durchlauf. Nicht mehr, wenn später das resize-Event behandelt wird. Um Fehler im Resize-Handler mit try/catch zu behandeln, musst Du in dieser Funktion einen eigenen try/catch aufbauen.
Rolf
Hallo Rolf!
Du bindest das Script mit defer ein - okay. Damit gibt's keine Probleme mit einer Race Condition.
Wenn Du das auf den Kommentar in Zeile 73 beziehst (der nichts mit der const-Problematik zu tun hat): Die Bildhöhe wird mit CSS an die Bildschirmgröße angepaßt. in Zeile 73 weiß es (nur) Safari offenbar noch nicht, daß das Bild per CSS evtl. kleiner wurde und die Berechnung Bild[0].height / 500
ergibt immer 1
. Also wird das später nochmal wiederholt.
- function trans referenziert xy. Solange es trans gibt, gibt es xy (trans bildet eine Closure und sollte den try-Scope einschließen)
- Der resize-Handler referenziert trans. Solange es den resize-Handler gibt, gibt es trans (der resize-Handler bildet eine closure, die trans und auch xy einschließt)
- der resize-Handler wurde an window.onresize zugewiesen. Damit sollte er bis zu einer anderen Zuweisung oder bis zum Reload der Seite existieren.
Testseite ohne onresize
, keine Änderung: peter-hindelang.de/Bilder/test30.html
Es ist MÖGLICH, dass diese Referenzbeziehungen, die xy (also dein BL) am Leben erhalten sollten, von Safari nicht korrekt beachtet werden. Ich habe das gerade in Chrome/Android betrachtet, da wird es korrekt erhalten. Safari kann ich nicht testen. Kann es sein, dass die JavaScript-Engine von Safari Closures nur auf Funktionsscope-Ebene bildet?
Ich hab eine Testseite gemacht mit onresize, ohne try/catch, scheint es zu funktionieren:
peter-hindelang.de/Bilder/test31.html Müßte man ausführlich testen.
Was würde daraus folgen? Ist es allgemein so, wie Du schreibst:
Kann es sein, dass die JavaScript-Engine von Safari Closures nur auf Funktionsscope-Ebene bildet?
Wäre das nicht ein kapitaler Browserfehler, der allgemein bekannt sein sollte? Bei bugs.webkit.org hatte ich auch mal gesucht, aber wohl kaum die richtigen Begriffe verwendet. (Letztenendes werd ich sowieso bei var
bleiben müssen, insbesondere weil ich den problematischen Browser nicht selber testen kann)
j.j.
Hallo j.j.,
die Race Condition bezog sich auf nichts konkretes. Ist halt nur so dass man beim Einbinden von Scripten Timingfehler machen kann. Aber du hast sie vermieden, meine ich.
Defer-Scripte laufen vor dem DOMContentLoaded Event, aber vor der ersten Layout-Phase. Anpassungen von Elementen an den Viewport kommen deshalb danach.
Im übrigen habe ich ja auch keinen Safari.
Wie machst du deine Screenshot-Tests?
Rolf
Hallo an alle!
peter-hindelang.de/Bilder/test31.html (Test ohne try/catch) scheint zu funktionieren. Vielleicht kann Gunnar Bittersmann mit seinem Mac nochmal testen.
Für mich ist die Sache vorerst erledigt. Ich hab jetzt und vor drei Wochen genug Zeit verbracht und auch noch euch behelligt.
Zusammenfassung:
script.js
nur funktioniert wenn ich var
statt const
verwende oder try/catch
weglassej.j.
Wie machst du deine Screenshot-Tests?
Rolf
Nebenbei: peter-hindelang.de ist ein Low-Budget-Projekt. Da ist ein 30$-Plan bei den einschlägigen Diensten nicht drin.
Ich glaube bei browserstack.com kann man mit einen Gratiskonto 3-Sekunden-Tests machen, aber das verwende ich nicht.
Die langjährige Erfahrung zeigt, daß kostenlose Dienste für Safari-Screenshots schnell dicht sind (überlastet/geschlossen/kostenpflichtig), sobald sie sich rumgesprochen haben. Ich verwende derzeit zwei und sende Dir morgen eine private Nachricht. Jetzt muß ich ins wirkliche Leben.
j.j.
Wie machst du deine Screenshot-Tests?
Rolf
Seh grad, kann keine E-Mail senden weil keine Adresse angegeben. Z.B. webpagetest loc NY