Eingehende Analyse des Dual-Thread-Modells in Miniprogrammen

青灯夜游
Freigeben: 2022-01-30 09:00:31
nach vorne
4128 Leute haben es durchsucht

Dieser Artikel hilft Ihnen, das Dual-Thread-Modell in WeChat-Miniprogrammen zu verstehen. Sprechen wir darüber, was das Dual-Thread-Modell von Miniprogrammen ist. Warum verwendet das Applet nicht das Threading-Modell des Browsers, sondern das Dual-Threading-Modell? Ich hoffe, es ist für alle hilfreich!

Eingehende Analyse des Dual-Thread-Modells in Miniprogrammen

Freunde, die Erfahrung in der WeChat-Applet-Entwicklung haben, sollten alle das Konzept des „Dual-Threaded-Modells“ kennen. Dieser Artikel fasst kurz einige populärwissenschaftliche Kenntnisse über das Dual-Thread-Modell zusammen Fehler, bitte korrigieren Sie mich.

Ich habe früher im Team „Mini Program·Cloud Development“ gearbeitet. Bei einigen externen Schulungen und beim Technologieaustausch wurde mir oft die Frage gestellt: „Was ist der wichtigste technische Unterschied zwischen dem WeChat Mini-Programm und der Web-Website?“ Aufgrund der Programmiersprache und des Paradigmas ist die Entwicklung kleiner Programme der Web-Front-End-Entwicklung sehr ähnlich (z. B. verwenden beide die JavaScript-Sprache, WXML/WXSS, die HTML/CSS usw. sehr ähnlich ist), werden jedoch nicht direkt verwendet native Frontend-Technologie. [Verwandte Lernempfehlungen: Tutorial zur Entwicklung von Miniprogrammen]

Im Vergleich zu Web-Websites müssen auf WeChat gehostete Miniprogramme Sicherheit, Leistung und andere Faktoren berücksichtigen, um sicherzustellen, dass Miniprogramme keine Sicherheitsrisiken für die WeChat-App selbst darstellen , wobei versucht wird, eine Leistung und Benutzererfahrung zu erreichen, die denen nativer Anwendungen nahe kommt. Dies sind die beiden Hauptgründe, warum kleine Programme das Thread-Modell des Browsers nicht direkt verwenden und selbst ein Dual-Thread-Modell erstellen müssen.

Was ist also das Dual-Thread-Modell kleiner Programme?

Der beste Weg, ein neues Konzept oder eine neue Technologie zu verstehen, besteht darin, ihm eine Referenz zu geben. Um das Threading-Modell eines kleinen Programms zu verstehen, müssen Sie daher zunächst ein gewisses Verständnis für das Threading-Modell des Browsers haben.

Browser sind Multiprozess-Browser

Vielleicht wurde jeder Front-End-Ingenieur bei seinem Einstieg in die Branche mehr als einmal gefragt: „Wie verstehen Sie den Single-Thread des Front-Ends aufgrund der JavaScript-Sprache?“ Eine der Kernkompetenzen des Front-Ends ist Single-Threading. Das vollständige Verständnis und die Beherrschung der Funktionsweise von JS-Single-Threads ist die grundlegendste Voraussetzung für einen Front-End-Ingenieur. Es gibt jedoch ein Missverständnis, in das viele Anfänger leicht verfallen: Sie verstehen „JavaScript Single-Threaded“ fälschlicherweise als „Browser Single-Threaded“.

Tatsächlich ist die interne Architektur des Browsers sehr komplex, aber er verwendet ein sich gegenseitig ausschließendes und blockierendes Verwaltungsmodell, um den GUI-Rendering-Thread und den JavaScript-Logik-Skript-Thread zu verwalten, was bei einigen Entwicklern zu Missverständnissen geführt hat.

Nehmen Sie den Chrome-Browser als Beispiel. Klicken Sie auf die Schaltfläche „Einstellungen“ in der oberen rechten Ecke und geben Sie dann „Weitere Tools“ -> „Task-Manager“ ein Sie können sehen, wie viele Chrome-Optionen geöffnet sind. Prozesse, einschließlich Browserprozesse, Netzwerkprozesse, GPU-Prozesse usw., sind allesamt gängige Prozesse.

Bitte beachten Sie: Im Bild oben gibt es zwei Tab-Prozesse (Renderer-Prozess) für jede Tab-Seite. Die Ressourcen (CPU, Speicher usw.) und Verhaltensweisen (UI) zwischen jedem Prozess und jeder Logik usw.) werden nicht miteinander geteilt. Selbst wenn eine Tab-Seite abstürzt, hat dies keine Auswirkungen auf andere Tab-Seiten.

In jedem Tab-Prozess übergibt der Browser verschiedene Aufgaben an die entsprechenden Threads. Beispielsweise ist der GUI-Rendering-Thread für das Rendern von HTML in eine visuelle Benutzeroberfläche verantwortlich; der JavaScript-Engine-Thread ist für das Parsen und Ausführen der JavaScript-Codelogik verantwortlich; Timing-Trigger Der Programmierthread ist für die Verarbeitung von setTimeout/setInterval-Timern usw. verantwortlich.

Eine weitere Sache: Es gibt eine Stelle, an der man leicht verwirrt werden kann. Tatsächlich ist setTimeout/setInterval nicht Teil der JavaScript-Sprache, sondern eine von der Laufzeit bereitgestellte Funktion (ursprünglich der Browser und später Node.js). unterstützt es auch).

Der GUI-Rendering-Thread und der JavaScript-Engine-Thread schließen sich gegenseitig aus. Selbst wenn die Ausführungszeit des Skripts zu lang ist, kommt es zu einem Absturz, da die Seite längere Zeit nicht reagiert Es sind der GUI-Rendering-Thread und die JavaScript-Engine, die diese gegenseitige Ausschluss- und Blockierungs-Thread-Verwaltungsmethode zwischen Threads dazu führen, dass einige Front-End-Entwickler denken, dass der Browser Single-Threaded ist.

Warum ist JavaScript also für Single-Threading konzipiert?

Der Gründer von JavaScript brauchte nur 10 Tage, um diese Sprache zu erstellen. Ursprünglich bestand seine Idee darin, eine einfache Skriptlogik im Browser bereitzustellen, um Benutzerinteraktion, DOM-Operationen usw. zu verwalten, daher muss das Design zwei Punkten folgen:

Einfache Syntax;

    Einfacher Bedienmechanismus.
  • In Bezug auf die Syntax lehnt sich JavaScript an Java an, entfernt jedoch viele komplexe Einstellungen, wie Typdeklarationen, Modulsysteme (später hinzugefügt) usw.
  • In Bezug auf den Ausführungsmechanismus bietet JavaScript keine Multithreading-Funktionen wie Java. Der Hauptgrund besteht darin, UI-Konflikte zu vermeiden, die durch Multithread-DOM-Operationen verursacht werden. Wenn beispielsweise mehrere Threads gleichzeitig dasselbe DOM betreiben, wie sollte der Browser dann bestimmen, welcher Thread verwendet wird, um den endgültigen UI-Effekt zu erzeugen? Dies ist ein klassisches Thread-Sicherheitsproblem (auch als Thread-Synchronisation bekannt). Im Bereich der Multithread-Programmierung gibt es viele Lösungen, z. B. das Hinzufügen von Sperrmechanismen, aber dies bringt im Gegensatz zum einfachen und benutzerfreundlichen Design mehr Komplexität mit sich von JavaScript Es widerspricht der ursprünglichen Absicht.

    Dies erklärt auch, warum sich der GUI-Rendering-Thread und der JavaScript-Engine-Thread gegenseitig ausschließen: JavaScript-Code hat die Berechtigung, das DOM zu ändern.

    Wenn JavaScript-Code ausgeführt wird, wird der GUI-Rendering-Thread angehalten und wartet vor der Ausführung darauf, dass der JavaScript-Engine-Thread inaktiv ist, um unnötigen Rendering-Druck zu vermeiden, der durch wiederholte Änderungen des DOM durch JavaScript während des Renderings verursacht wird. Durch die Verwendung eines sich gegenseitig ausschließenden Modus zum Warten auf den Abschluss der Ausführung des JavaScript-Codes kann sichergestellt werden, dass das Rendering das endgültige Ausführungsergebnis ist. Daher ist die Leerlaufzeit des Browsers auch zu einem wichtigen Indikator für die Messung der Website-Leistung geworden. Die Leerlaufzeit zeigt meist an, dass die JavaScript-Logik nicht intensiv ist und die Häufigkeit von DOM-Änderungen gering ist. In diesem Fall kann der Browser auf Benutzerinteraktionen reagieren schneller und reibungsloser. Das Verhalten ist wie folgt:

    React Fiber nutzt Leerlaufzeit, um Sharding-Aufgaben zu verarbeiten.

    Später führte HTML5 den Web Worker ein, der die Möglichkeit bietet, JavaScript-Code in mehreren Threads auszuführen. Im Gegensatz zu anderen Programmiersprachen läuft der Worker-Thread jedoch nicht parallel zum Haupt-Thread, sondern ist eine Art Master-Slave -Gewindemodell. Der JavaScript-Code in

    Worker kann das DOM nicht bedienen und kann als Thread-sicher verstanden werden. Behalten Sie dies im Hinterkopf. Dies ist eine wichtige Grundlage für das später besprochene Dual-Thread-Modell kleiner Programme.

    Warum nutzen WeChat-Miniprogramme nicht direkt das Threading-Modell des Browsers? Dazu ist ein Vergleich der Unterschiede zwischen Miniprogrammen und Web-Websites sowohl aus Produkt- als auch aus technischer Sicht erforderlich.

    Warum verwenden Miniprogramme nicht das Threading-Modell des Browsers?

    Als ich zum ersten Mal mit der Entwicklung von Miniprogrammen in Kontakt kam, gefielen mir oft die im Vergleich zum Web abgeschwächten Fähigkeiten und die im Vergleich zu Vue zu einfache Syntax. Damals hatte ich fast das Gefühl, dass Miniprogramme das technologische Monopol von WeChat darstellten, das auf der großen Anzahl an Nutzern beruhte.

    Mit dem kontinuierlichen tiefgreifenden Verständnis von Technologie und Produkten hat sich jedoch auch meine Einstellung gegenüber Miniprogrammen geändert, von „Abneigung“ zu Bewunderung, denn nachdem ich die Produktpositionierung von Miniprogrammen vollständig verstanden hatte, fand ich Double Das Thread-Modell ist die optimale Lösung in Produktszenarien wie kleinen Programmen. Was für ein Produkt ist das Miniprogramm?

    Der Host des Miniprogramms ist WeChat, aber die Iteration der Miniprogrammversion ist unabhängig und Upgrades und Updates hängen nicht vom Host ab. Dies ist dasselbe wie bei der Web-Website. Mit anderen Worten, Miniprogramme erben einige der Vorteile des Webs, sind aber nicht das Web. Derzeit sind webbezogene Technologien recht umfassend und können einige sehr große Anwendungen wie 3D-Karten, Spiele usw. hosten.

    Die Positionierung von Miniprogrammen soll klein und schön sein und nach der Verwendung verschwinden. Es nutzt nicht alle Webfunktionen in WeChat aus und ist daher in Bezug auf die Funktionen dem Web definitiv unterlegen verfügt über einige native Funktionen, die von WeChat bereitgestellt werden, z. B. native Funktionen, APIs auf Systemebene und WeChat-Ökosystem.

    Darüber hinaus unterscheidet sich die Beziehung zwischen „Miniprogramm-WeChat“ von der Beziehung zwischen „Website-Browser“. Ersteres liegt näher an jedem Programmfall (als Fall bezeichnet) in Online-Programmierplattformen wie CodePen und JSFiddler ( im Unterricht als Plattform bezeichnet).

    Aus technischer Sicht besteht eine der Kernüberlegungen der Plattform darin, sicherzustellen, dass die Logik des Falles die Sicherheit der Plattform nicht gefährdet und gleichzeitig ausreichende Fähigkeiten für den Fall bereitstellt. Stellen Sie sich vor, Sie könnten ein Programm auf CodePen schreiben, um an die privaten Informationen von CodePen zu gelangen. Vielleicht würde CodePen am nächsten Tag abstürzen und alle Mitarbeiter entlassen. Bei einem solchen Produktton ist der nächste Schritt bei der Technologieauswahl die Arbeit von Architekten und Programmierern.

    Nehmen wir CodePen als Beispiel. Wenn Sie gebeten würden, eine solche Programmierplattform zu entwerfen, welche Technologie würden Sie verwenden?

    Vielleicht ist Ihr erster Gedanke die Verwendung von Iframe, da alle Webfunktionen innerhalb von Iframe genutzt werden können. Tatsächlich verwendet CodePen iframe, um den Programmeffekt darzustellen, aber es kopiert den eingegebenen JavaScript-Code nicht vollständig zur Ausführung in den iframe. Stattdessen durchläuft der Code einen Kompilierungsprozess, bevor er in den iframe eingefügt wird. Dies basiert hauptsächlich auf Sicherheitsüberlegungen, und zweitens werden einige gefährliche Codes während des Kompilierungsprozesses entfernt. Dadurch können auch weitere Sprachen in der Plattform unterstützt werden, z. B. Typoskript. Natürlich gibt es auch Leistungsprobleme, die bei Iframes häufig auftreten, daher werde ich nicht näher darauf eingehen.

    Sie müssen also nicht nur iframe verwenden, sondern auch einen zusätzlichen JavaScript-Compiler einführen. CodePen muss sicherstellen, dass der JavaScript-Code in jedem Fall threadsicher ist. Die einfachste Möglichkeit besteht darin, dem Programm den Betrieb des DOM der CodePen-Website zu verbieten. Es gibt zwei Möglichkeiten, dies zu erreichen:

    • Eine ist Web Worker.

    • Die andere Möglichkeit besteht darin, Shadow DOM zu verwenden.

    Web Worker ist threadsicher. Der JavaScript-Code im Worker kann die Window- und Document-Objekte nicht abrufen und daher das DOM nicht bedienen. Darüber hinaus blockiert der Code im Worker aufgrund der Thread-Sicherheitsfunktion von Worker während der Ausführung nicht den äußeren GUI-Rendering-Thread, und beide können parallel ausgeführt werden.

    Shadow DOM ist Teil der Web Components-Spezifikation. Wenn Sie den Modus von ShadowRoot auf closed setzen, wird verhindert, dass der ShadowRoot-Knoten abgerufen wird, und daher kann das interne DOM nicht manipuliert werden.

    Im Vergleich der beiden weist Shadow DOM eine schlechtere Kompatibilität als Web Worker auf und ist noch weit von einer groß angelegten Verwendung entfernt, sodass die Web Worker-Lösung realistischer ist.

    Dies bildet ein einfaches Zwei-Thread-Modell: Der Worker-Thread ist für die Berechnung verantwortlich, leitet die Ergebnisse über postMessage an den Haupt-Thread weiter, und der Haupt-Thread ist für das Rendern verantwortlich.

    Dieses Modell weist jedoch schwerwiegende Leistungsprobleme auf. Zusätzlich zum Rechenverbrauch hat der Kommunikationsprozess mit dem Hauptthread auch sehr schwerwiegende Auswirkungen auf die Leistung.

    Gibt es also eine Möglichkeit, die gleiche Thread-Sicherheit wie Web Worker zu erreichen und gleichzeitig die Leistung zu berücksichtigen und eine gute Benutzererfahrung zu gewährleisten? Dies ist der Hauptzweck der Verwendung des Dual-Thread-Modells für das WeChat-Applet.

    Sicheres und effizientes Dual-Thread-Modell

    Obwohl früher Programmierplattformen wie CodePen als Analogie verwendet wurden, sind die technischen Anforderungen von Miniprogrammen und CodePen nicht genau die gleichen. Der Hauptunterschied besteht darin, dass Miniprogramme keine Unterstützung benötigen Alle HTML-Tags, nur eine begrenzte Anzahl von Arten von UI-Komponenten werden bereitgestellt. Entsprechend der Produktpositionierung des Miniprogramms können wir die wichtigsten technischen Anforderungen des Miniprogramms wie folgt zusammenfassen. (Jede neue Technologie oder Architektur soll bestimmte Probleme lösen, daher ist es notwendig, die wichtigsten technischen Anforderungen des Miniprogramms zu verstehen.)

    • Beschränken Sie die UI-Komponententypen, um nur die Deklaration einiger bestimmter Komponenten zu ermöglichen

      Das Miniprogramm verwendet bei der Deklaration von Komponenten keine nativen HTML-Tags, sondern kann nur mehrere integrierte Basiskomponenten verwenden, die von WeChat bereitgestellt werden. Natürlich können Sie Komponenten auch anpassen, dies wird jedoch auch durch eine Kombination erreicht der eingebauten Grundkomponenten.

    • Gewährleistet die Sicherheit logischer Threads und ermöglicht keine direkte Manipulation von UI-Komponenten.

      Die Art und Weise, wie Miniprogramme die Benutzeroberfläche aktualisieren, ähnelt MVVM-Frameworks wie Vue/React. JavaScript-Code kann das DOM nicht direkt bedienen (nur zur Analogie). Tatsächlich gibt es in Miniprogrammen kein DOM-Konzept, aber die Benutzeroberfläche wird asynchron durch Aktualisieren des Status (setState) aktualisiert. In diesem Prozess werden VDOM und ein effizienter Diff-Algorithmus verwendet (diese beiden Punkte werden nicht berücksichtigt). besprechen, Sie können nach dem Unterricht selbst danach suchen) (relevante Informationen).

    • Kann online aktualisiert werden, ohne auf WeChat angewiesen zu sein

      Der Host des Miniprogramms ist WeChat. Wenn es mit reinem Native implementiert wird, muss das Versionsupdate des Miniprogramms auf WeChat basieren und zusammen mit veröffentlicht werden Der WeChat-Code wird definitiv nicht funktionieren. Handelt es sich um eine reine Web-Implementierung, lassen sich Sicherheit und Performance nur schwer garantieren.

      Miniprogramme müssen in der Lage sein, Ressourcen wie das Web in der Cloud zu hosten und gleichzeitig unabhängig aktualisiert zu werden. Sie müssen in der Lage sein, ausreichend Sicherheit und Leistung zu gewährleisten. Letztendlich hat das Applet ein gemischtes Architekturmodell übernommen: Verwenden Sie Webview zum Rendern der Benutzeroberfläche und verwenden Sie unabhängige Threads ähnlich wie Web Worker, um die Logik auszuführen. Dies ist das Dual-Thread-Modell.

    • Die Leistung muss so weit wie möglich verbessert werden, um die Benutzererfahrung zu gewährleisten

      Die Leistung des zuvor erwähnten einfachen Dual-Thread-Modells auf Basis von Web Worker ist ein großes Problem Das Programm verwendet keine untergeordneten Web-Worker-Threads. Es handelt sich um einen unabhängigen „Hauptthread“, der eine relativ gute Leistung gewährleisten kann.

    Rendering-Thread und Logik-Thread

    Die beiden Threads des Applets beziehen sich auf den Rendering-Thread und den Logik-Thread. Diese beiden Threads sind für das Rendern der Benutzeroberfläche bzw. die Ausführung von JavaScript-Code verantwortlich. Wie in der folgenden Abbildung dargestellt:

    Der Rendering-Thread verwendet Webview zum Rendern der Benutzeroberfläche. Webview ist eine vollständige browserähnliche Ausführungsumgebung mit der Möglichkeit, JavaScript auszuführen. Das Applet legt das Logikskript jedoch nicht zur Ausführung in Webview ab, sondern trennt die Logikschicht in einen Thread parallel zu Webview und verwendet den Client zur Bereitstellung von JavaScript Die Engine führt den Code, die JavaScriptCore-Umgebung von iOS, die JsCore-Umgebung von Android und das nwjs-IDE-Tool aus, das vom X5-Kernel von Tencent bereitgestellt wird.

    Der logische Thread ist eine Sandbox-Umgebung, die nur JavaScript ausführen kann. Er stellt keine APIs für DOM-Operationen bereit und kann daher die Benutzeroberfläche nur asynchron aktualisieren, indem er Daten über setData aktualisiert.

    Ereignisgesteuerte Kommunikationsmethode

    Achten Sie auf die Kommunikationsmethode zwischen dem Rendering-Thread und dem Logik-Thread in der obigen Abbildung. Anders als bei Vue/React handelt es sich um die Kommunikation zwischen der Rendering-Schicht und der Logikschicht des Applets Daten oder Ereignisse werden nicht zwischen zwei Benutzern direkt übertragen, sondern von Native als Vermittler weitergeleitet.

    Der gesamte Prozess ist ein typisches ereignisgesteuertes Modell:

      Die Rendering-Ebene (kann auch als Ansichtsebene bezeichnet werden) löst durch Interaktion mit dem Benutzer bestimmte Ereignisse aus.
    • Dann wird das Ereignis an übergeben die Logikschicht;
    • Die Logikschicht übergibt die verarbeiteten Daten dann durch eine Reihe logischer Verarbeitung, Datenanforderungen, Schnittstellenaufrufe und anderer Verhaltensweisen.
    • Die letzte Renderingschicht rendert die Daten in ein visuelles Bild Benutzeroberfläche.
    • Dieses datengesteuerte UI-Modell ist mittlerweile ein angeseheneres Programmierparadigma im Bereich der Front-End-Programmierung. Wenn Sie ein Front-End-Entwickler mit mehr als 5 Jahren Entwicklungserfahrung sind, dann glaube ich, dass Sie es auf jeden Fall sein werden Wenn Sie diesem Modell zum ersten Mal ausgesetzt sind, gibt es einige Unannehmlichkeiten, da die Funktionsweise von JavaScript zuvor fast eine „Branchenregel“ war. Es gibt sogar viele Bücher, Blogs und Lehrbücher für den Einstieg in das Frontend Das beginnt mit dem DOM-Betrieb. Nun scheint es, dass diese tatsächlich etwas veraltet sind.

    Einerseits kann dieser Thread-Aufteilungsmodus, der Logik und Rendering trennt, sicherstellen, dass der in der logischen Thread-Sandbox ausgeführte JavaScript-Code threadsicher ist. Andererseits ist der Berechnungsaufwand des Rendering-Threads sehr gering. Es stellt sicher, dass das Benutzerinteraktionsverhalten sicher ist. Eine schnelle Reaktion verbessert das Benutzererlebnis.

    Im Vergleich zum Thread-Modell des Browsers löst oder vermeidet das Dual-Thread-Modell des Miniprogramms die besorgniserregende Leistung des Web Workers und erreicht gleichzeitig die gleiche Thread-Sicherheit wie der Web Worker, sowohl hinsichtlich der Leistung als auch der Sicherheit wurde aus mehreren Blickwinkeln erreicht. Zusammenfassend lässt sich sagen, dass der

    Dual-Threaded-Modus eine verbesserte Architekturlösung innerhalb des spezifischen Szenarios kleiner Programme ist, die durch das bestehende Prozess- und Thread-Verwaltungsmodell des Browsers eingeschränkt ist

    . Zusammenfassung

    Meiner Meinung nach besteht die Kernkompetenz und Wettbewerbsfähigkeit von Programmierern nicht darin, die API einer bestimmten Sprache oder eines bestimmten Frameworks vollständig zu verstehen, sondern in der Kenntnis der zugrunde liegenden Prinzipien dieser Sprachen und Frameworks. Für einen kleinen Programmentwickler basiert die Lösung bei technischen Problemen bei der Arbeit oft auf den zugrunde liegenden Prinzipien (noch einfacher: Wenn Sie auf der Suche nach einem Vorstellungsgespräch sind, wird Sie niemand nach der Syntax des kleinen Programms fragen).

    Durch das Verständnis des Hintergrunds, des Designs und der Kommunikation des Dual-Thread-Modells des Miniprogramms hoffe ich, dass jeder ein tieferes Verständnis der zugrunde liegenden Architektur des Miniprogramms erlangen kann. Es kann auch als Referenz verwendet werden, falls vorhanden Bedarf für ähnliche Szenarien in späteren Arbeiten. Natürlich ist das Verständnis des Dual-Thread-Modells kleiner Programme nicht das einzige Ziel. Dieses Wissen kann in gewissem Maße Inspiration für die tägliche Entwicklungsarbeit sein, vor allem im Hinblick auf die Leistung:

      Versuchen Sie, einfache Strukturen zu verwenden und gleichzeitig sicherzustellen Funktionalität.
    • Versuchen Sie, die Komplexität der JavaScript-Logik zu reduzieren.
    • Versuchen Sie, die Häufigkeit von setData-Aufrufen und die übertragene Datenmenge zu reduzieren.
    • Weitere Programmierkenntnisse finden Sie unter:
    Programmiervideo

    ! !

Das obige ist der detaillierte Inhalt vonEingehende Analyse des Dual-Thread-Modells in Miniprogrammen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:cnblogs.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage