Heim  >  Artikel  >  Web-Frontend  >  Informationen zur Verwendung von Beispielen für die synchrone und asynchrone JavaScript-Programmierung

Informationen zur Verwendung von Beispielen für die synchrone und asynchrone JavaScript-Programmierung

伊谢尔伦
伊谢尔伦Original
2017-06-16 10:20:012186Durchsuche

Wenn Sie Javascript gründlich lernen möchten, schauen Sie sich den folgenden Artikel an, er könnte für Sie hilfreich sein.

Vorwort

Wenn Sie entschlossen sind, ein hervorragender Front-End-Ingenieur zu werden oder JavaScript eingehend erlernen möchten, ist asynchrone Programmierung ein wesentlicher Wissenspunkt, und das ist es auch Unterscheidet Anfänger, eine der Grundlagen für Fortgeschrittene oder Fortgeschrittene. Wenn Sie kein klares Konzept für die asynchrone Programmierung haben, empfehle ich Ihnen, sich etwas Zeit mit dem Erlernen der asynchronen Programmierung in JavaScript zu nehmen. Wenn Sie über ein eigenes, einzigartiges Verständnis der asynchronen Programmierung verfügen, können Sie diesen Artikel gerne lesen und gemeinsam kommunizieren.

Synchronisation und Asynchronität

Bevor wir die asynchrone Programmierung einführen, schauen wir uns an, dass die sogenannte synchrone Programmierung bedeutet, dass der Computer Code Zeile für Zeile ausführt. Die zeitaufwändige Ausführung der aktuellen Codeaufgabe blockiert die Ausführung des nachfolgenden Codes.

Synchronisierte Programmierung ist ein typisches Anfrage-Antwort-Modell. Wenn eine Anfrage eine Funktion oder Methode aufruft, muss sie auf die Rückgabe ihrer Antwort warten und dann den folgenden Code ausführen.

Unter normalen Umständen kann die synchrone Programmierung, bei der der Code der Reihe nach ausgeführt wird, die Ausführung des Programms durchaus sicherstellen. In einigen Szenarien, z. B. beim Lesen von Dateiinhalten oder beim Anfordern von Serverschnittstellendaten, kann dies jedoch durchaus der Fall sein. Nachfolgende Vorgänge müssen basierend auf dem Inhalt der zurückgegebenen Daten ausgeführt werden. Der Prozess des Lesens der Datei und des Anforderns der Schnittstelle bis zur Rückgabe der Daten dauert. Je schlechter das Netzwerk, desto länger dauert es Beim Programmieren wird die Zeit, die mit dem Warten auf die Rückgabe der Daten verbracht wird, nicht verarbeitet. Zu diesem Zeitpunkt werden auch alle Vorgänge wie Seiteninteraktion und Scrollen blockiert. Dies ist offensichtlich äußerst unfreundlich und inakzeptabel Wo die asynchrone Programmierung ihre Talente zeigen muss, wie unten gezeigt, blockiert die zeitaufwändige Aufgabe A die Ausführung von Aufgabe B und kann B nicht weiter ausführen, bis Aufgabe A abgeschlossen ist:

Informationen zur Verwendung von Beispielen für die synchrone und asynchrone JavaScript-Programmierung

Warten Sie bei Verwendung der asynchronen Programmierung, bis die Antwort der aktuellen Aufgabe zurückkehrt, bevor Sie zurückkehren. Sie können den nachfolgenden Code weiterhin ausführen, dh die aktuelle Ausführungsaufgabe blockiert die nachfolgende Ausführung nicht.

Asynchrone Programmierung unterscheidet sich vom Anforderungs-Antwort-Modus der synchronen Programmierung. Es handelt sich um eine Art ereignisgesteuerte Programmierung. Nachdem die Anforderung eine Funktion oder Methode aufgerufen hat, muss nicht gewartet werden Sie erhalten sofort eine Antwort und können mit anderen Aufgaben fortfahren. Nachdem die Aufgabenantwort zurückgegeben wurde, kann der Anrufer über Status, Benachrichtigungen und Rückrufe benachrichtigt werden.

Multithreading

Wie bereits erläutert, kann die asynchrone Programmierung das Problem der Blockierung bei der synchronen Programmierung effektiv lösen. Der übliche Weg, eine asynchrone Implementierung zu erreichen, ist Multithreading, wie z. B. C#, das heißt, mehrere Threads werden gleichzeitig gestartet und verschiedene Vorgänge können parallel ausgeführt werden. Wie in der Abbildung unten gezeigt, ist Aufgabe A zeitaufwändig ausgeführt wird, kann Aufgabe B auch in Thread zwei ausgeführt werden:

Informationen zur Verwendung von Beispielen für die synchrone und asynchrone JavaScript-Programmierung

JavaScript Single-Threaded

Die JavaScript-Sprachausführungsumgebung ist Single-Threaded Ein einzelner Thread führt ein Programm aus, die verwendeten Programmpfade sind in aufeinanderfolgender Reihenfolge angeordnet und die vorherigen müssen verarbeitet werden. Nun, die späteren werden ausgeführt, und bei Verwendung der asynchronen Implementierung können mehrere Aufgaben gleichzeitig ausgeführt werden. Wie implementiert man also asynchrone Programmierung in JavaScript? Im nächsten Abschnitt wird der asynchrone Mechanismus erläutert.

Parallelität und Parallelität

Wie bereits erwähnt, können Multithread-Aufgaben parallel ausgeführt werden, während die asynchrone JavaScript-Single-Thread-Programmierung die gleichzeitige Ausführung mehrerer Aufgaben erreichen kann. Es ist notwendig, den Unterschied zwischen Parallelität zu erklären und Parallelität.

  • Parallel bezieht sich auf die gleichzeitige Ausführung mehrerer Aufgaben.

  • Parallelität bezieht sich auf die gleichzeitige Ausführung mehrerer Aufgaben innerhalb derselben Zeitraum. Zu einem bestimmten Zeitpunkt wird jedoch nur eine bestimmte Aufgabe ausgeführt.

Die Anzahl gleichzeitiger Verbindungen bezieht sich normalerweise auf die Häufigkeit, mit der der Browser eine Anfrage an den Server initiiert und aufbaut eine TCP-Verbindung, und der Server stellt sie pro Sekunde her. Die Gesamtzahl der Verbindungen. Wenn der Server eine Verbindung in 10 ms verarbeiten kann, beträgt die Anzahl gleichzeitiger Verbindungen 100.

Asynchroner JavaScript-Mechanismus

In diesem Abschnitt wird der asynchrone JavaScript-Mechanismus vorgestellt:

    for (var i = 0; i < 5; i ++) {
        setTimeout(function(){
            console.log(i);
        }, 0);
    }
    console.log(i);
    //5 ; 5 ; 5 ; 5; 5

Sie sollten verstehen, dass die endgültige Ausgabe alle 5 ist:

  1. i hier ist die Variable des Kontexts, in dem sich die for-Schleife befindet, und es gibt nur ein i;

  2. i==5 at das Ende der Schleife;

  3. Der JavaScript-Single-Thread-Ereignishandler führt das nächste Ereignis erst aus, wenn der Thread inaktiv ist.

Wie im dritten Punkt oben erwähnt, müssen Sie die JavaScript-Ereignisschleife und das Parallelitätsmodell verstehen, wenn Sie setTimeout() im obigen Beispiel und den asynchronen JavaScript-Mechanismus wirklich verstehen wollen .

Parallelitätsmodell

Derzeit wissen wir bereits, dass JavaScript bei der Ausführung einer asynchronen Aufgabe nicht auf die Rückkehr der Antwort warten muss und weiterhin andere Aufgaben ausführen kann Wenn die Antwort zurückgegeben wird, erhalten Sie eine Benachrichtigung, einen Ausführungsrückruf oder einen Ereignishandler. Wie genau wird das alles gemacht und nach welchen Regeln bzw. in welcher Reihenfolge funktioniert es? Als nächstes müssen wir diese Frage beantworten.

Hinweis: Es gibt im Wesentlichen keinen Unterschied zwischen Callbacks und Event-Handlern, sie werden nur in verschiedenen Situationen unterschiedlich aufgerufen.

Wie bereits erwähnt, ermöglicht die asynchrone JavaScript-Programmierung die gleichzeitige Ausführung mehrerer Aufgaben. Die Grundlage für die Realisierung dieser Funktion ist, dass JavaScript über ein Parallelitätsmodell verfügt, das auf der Ereignisschleife basiert.

Stapel und Warteschlange

Bevor wir das JavaScript-Parallelitätsmodell vorstellen, stellen wir kurz den Unterschied zwischen Stapel und Warteschlange vor:

  • Heap: ein bestimmter Bereich in Speicher Ein nicht blockierter Bereich, in dem normalerweise Objekte (Referenztypen) gespeichert werden.

  • Stapel: eine Datenstruktur, die in der Reihenfolge „Last-In-First-Out“ gespeichert wird und normalerweise Funktionsparameter und Basistypwertvariablen speichert (Zugriff nach Wert);

  • Warteschlange (Warteschlange): Datenstruktur, die in der Reihenfolge „First-In, First-Out“ gespeichert wird.

Ereignisschleife

Die JavaScript-Engine ist für das Parsen und Ausführen von JavaScript-Code verantwortlich, kann jedoch nicht alleine ausgeführt werden. Sie erfordert normalerweise eine Host-Umgebung, normalerweise einen Browser oder Knotenserver, der oben erwähnte einzelne Thread bezieht sich auf die Erstellung eines einzelnen Threads in diesen Hostumgebungen und bietet einen Mechanismus zum Aufrufen der JavaScript-Engine, um die Planung und Ausführung mehrerer JavaScript-Codeblöcke abzuschließen (ja, JavaScript-Codes sind alle in Blöcken ( ausgeführt wird), wird dieser Mechanismus als Ereignisschleife (Event Loop) bezeichnet.

注:这里的事件与DOM事件不要混淆,可以说这里的事件包括DOM事件,所有异步操作都是一个事件,诸如ajax请求就可以看作一个request请求事件。

JavaScript执行环境中存在的两个结构需要了解:

  • 消息队列(message queue),也叫任务队列(task queue):存储待处理消息及对应的回调函数或事件处理程序;

  • 执行栈(execution context stack),也可以叫执行上下文栈:JavaScript执行栈,顾名思义,是由执行上下文组成,当函数调用时,创建并插入一个执行上下文,通常称为执行栈帧(frame),存储着函数参数和局部变量,当该函数执行结束时,弹出该执行栈帧;

注:关于全局代码,由于所有的代码都是在全局上下文执行,所以执行栈顶总是全局上下文就很容易理解,直到所有代码执行完毕,全局上下文退出执行栈,栈清空了;也即是全局上下文是第一个入栈,最后一个出栈。

任务

分析事件循环流程前,先阐述两个概念,有助于理解事件循环:同步任务和异步任务。

任务很好理解,JavaScript代码执行就是在完成任务,所谓任务就是一个函数或一个代码块,通常以功能或目的划分,比如完成一次加法计算,完成一次ajax请求;很自然的就分为同步任务和异步任务。同步任务是连续的,阻塞的;而异步任务则是不连续,非阻塞的,包含异步事件及其回调,当我们谈及执行异步任务时,通常指执行其回调函数。

事件循环流程

关于事件循环流程分解如下:

  1. 宿主环境为JavaScript创建线程时,会创建堆(heap)和栈(stack),堆内存储JavaScript对象,栈内存储执行上下文;

  2. 栈内执行上下文的同步任务按序执行,执行完即退栈,而当异步任务执行时,该异步任务进入等待状态(不入栈),同时通知线程:当触发该事件时(或该异步操作响应返回时),需向消息队列插入一个事件消息;

  3. 当事件触发或响应返回时,线程向消息队列插入该事件消息(包含事件及回调);

  4. 当栈内同步任务执行完毕后,线程从消息队列取出一个事件消息,其对应异步任务(函数)入栈,执行回调函数,如果未绑定回调,这个消息会被丢弃,执行完任务后退栈;

  5. 当线程空闲(即执行栈清空)时继续拉取消息队列下一轮消息(next tick,事件循环流转一次称为一次tick)。

使用代码可以描述如下:

    var eventLoop = [];    var event;    var i = eventLoop.length - 1; // 后进先出

    while(eventLoop[i]) {        event = eventLoop[i--]; 
        if (event) { // 事件回调存在
            event();
        }        // 否则事件消息被丢弃
    }

这里注意的一点是等待下一个事件消息的过程是同步的。

并发模型与事件循环
    var ele = document.querySelector(&#39;body&#39;);    function clickCb(event) {        console.log(&#39;clicked&#39;);
    }    function bindEvent(callback) {
        ele.addEventListener(&#39;click&#39;, callback);
    }    

    bindEvent(clickCb);

针对如上代码我们可以构建如下并发模型:

Informationen zur Verwendung von Beispielen für die synchrone und asynchrone JavaScript-Programmierung

如上图,当执行栈同步代码块依次执行完直到遇见异步任务时,异步任务进入等待状态,通知线程,异步事件触发时,往消息队列插入一条事件消息;而当执行栈后续同步代码执行完后,读取消息队列,得到一条消息,然后将该消息对应的异步任务入栈,执行回调函数;一次事件循环就完成了,也即处理了一个异步任务。

再谈Informationen zur Verwendung von Beispielen für die synchrone und asynchrone JavaScript-Programmierung

了解了JavaScript事件循环后我们再看前文关于Informationen zur Verwendung von Beispielen für die synchrone und asynchrone JavaScript-Programmierung的例子就比较清晰了:

Informationen zur Verwendung von Beispielen für die synchrone und asynchrone JavaScript-Programmierung所表达的意思是:等待0秒后(这个时间由第二个参数值确定),往消息队列插入一条定时器事件消息,并将其第一个参数作为回调函数;而当执行栈内同步任务执行完毕时,线程从消息队列读取消息,将该异步任务入栈,执行;线程空闲时再次从消息队列读取消息。

再看一个实例:

    var start = +new Date();    var arr = [];

    setTimeout(function(){        console.log(&#39;time: &#39; + (new Date().getTime() - start));
    },10);    for(var i=0;i<=1000000;i++){
        arr.push(i);
    }

执行多次输出如下:

Informationen zur Verwendung von Beispielen für die synchrone und asynchrone JavaScript-Programmierung

setTimeout异步回调函数里我们输出了异步任务注册到执行的时间,发现并不等于我们指定的时间,而且两次时间间隔也都不同,考虑以下两点:

  • 在读取消息队列的消息时,得等同步任务完成,这个是需要耗费时间的;

  • 消息队列先进先出原则,读取此异步事件消息之前,可能还存在其他消息,执行也需要耗时;

所以异步执行时间不精确是必然的,所以我们有必要明白无论是同步任务还是异步任务,都不应该耗时太长,当一个消息耗时太长时,应该尽可能的将其分割成多个消息。

Web Workers

每个Web Worker或一个跨域的iframe都有各自的堆栈和消息队列,这些不同的文档只能通过postMessage方法进行通信,当一方监听了message事件后,另一方才能通过该方法向其发送消息,这个message事件也是异步的,当一方接收到另一方通过postMessage方法发送来的消息后,会向自己的消息队列插入一条消息,而后续的并发流程依然如上文所述。

JavaScript异步实现

关于JavaScript的异步实现,以前有:回调函数,发布订阅模式,Promise三类,而在ES6中提出了生成器(Generator)方式实现,关于回调函数和发布订阅模式实现可参见另一篇文章,后续将推出一篇详细介绍Promise和Generator。

以上就是javascript同步与异步的全部内容了,感谢大家的阅读。Informationen zur Verwendung von Beispielen für die synchrone und asynchrone JavaScript-Programmierung


Das obige ist der detaillierte Inhalt vonInformationen zur Verwendung von Beispielen für die synchrone und asynchrone JavaScript-Programmierung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
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