Sequentielle Ausführung asynchroner Vorgänge in JavaScript-Funktionen von WeChat-Applets

1. Einleitung

Bei der Entwicklung kleiner Programme kommt es häufig vor, dass die letzte Operation vom asynchronen Ausführungsergebnis der vorherigen Operation abhängt. Obwohl JavaScript eine Single-Thread-Sprache ist, werden zeitaufwändige Vorgänge im Hauptthread normalerweise zur asynchronen Ausführung in die Aufgabenwarteschlange gestellt , um ein Blockieren des Hauptthreads zu vermeiden, zum Beispiel:

let f1 = function (sequence) {
  console.log("f1开始执行");
  setTimeout(function () {
    console.log("f1执行完成");
  },10)
}
let f2 = function (sequence) {
  console.log("f2开始执行");
  setTimeout(function () {
    console.log("f2执行完成");
  },30)
}
let f3 = function (sequence) {
  console.log("f3开始执行");
  setTimeout(function () {
    console.log("f3执行完成");
  },1)
}
let test=function(){
  f1();
  f2();
  f3();
}

Führen Sie die Testfunktion aus und stellen Sie fest, dass das Ausführungsergebnis wie folgt lautet:

 Es ist ersichtlich, dass der Konsolenteil in den Funktionen f1, f2 und f3 entsprechend der Aufrufreihenfolge im Test sequentiell ausgeführt wird, da dieser Teil des Codes im Hauptthread ausgeführt und synchron ausgeführt wird. Die Rückruffunktion von setTimeout wird nicht in der Reihenfolge des Aufrufs ausgeführt, da setTimeout zur asynchronen Ausführung in die Aufgabenwarteschlange gestellt wird , da die Ausführungszeit f3<f1<f2 beträgt , sodass setTimeout in f3 von der Aufgabenwarteschlange zur Hauptwarteschlange zurückkehrt Die Rückruffunktion wird im Thread ausgeführt und f2 kehrt schließlich zurück.

Weitere Informationen zur JavaScript-Ausführungsreihenfolge finden Sie unter: Front-End-Trockenware: JS-Ausführungsreihenfolge – JS-Betriebsmechanismus in einem kurzen Buch. Lassen Sie mich mit einer Interviewfrage aus den heutigen Schlagzeilen beginnen. 1. Single-Threaded-JavaScript-JS ist Single-Threaded. basierend auf Ereignisschleifen und nicht blockierenden E/As. Features: Handhabung von I/O-Anwendungen, nicht geeignet für CPU-intensive Vorgänge... https://www.jianshu.com/p/62c7d633a879

 Wenn die Ausführung von f2 vom Ausführungsergebnis der Rückruffunktion setTimeout in f1 abhängt und f3 vom Ausführungsergebnis in f2 abhängt , muss sichergestellt werden, dass die asynchronen Vorgänge in den drei Funktionen nacheinander ausgeführt werden, zum Beispiel: eine Operation Um den Vorgang abzuschließen, müssen nacheinander mehrere Netzwerkanfragen gestellt werden . Hier wird eine nicht blockierende Methode (der Hauptthread muss nicht warten) vorgeschlagen, um sicherzustellen, dass die asynchronen Vorgänge in den drei Funktionen nacheinander ausgeführt werden.

2. Verwenden Sie Polling, um sicherzustellen, dass asynchrone Vorgänge nacheinander ausgeführt werden

Um zu vermeiden, dass die UI-Schnittstelle des Applets blockiert, kann die Methode zum Blockieren des Hauptthreads nicht verwendet werden. Daher wird hier der setInterval- Timer verwendet, um asynchrone Abfragevorgänge zu implementieren und die sequentielle Ausführung asynchroner Vorgänge sicherzustellen. Definieren Sie zunächst die sequentielle Ausführungsklasse:

let SequentialExec=class SequentialExec {
  constructor(func_list) {
      //顺序执行函数列表
      this.func_list = func_list;
      // 计数器
      this.count = 0;
      // 函数执行标志
      this.running = false;
      //函数执行结果
      this.res = null;
      //定时器序号
      this.timer=null;
  }
  /**
   * 启动定时器轮询
   */
  wait(){
    if(!this.timer){
    // 启动定时器轮询next方法
      this.timer=setInterval(this.next,5,this)
    }
  }
  /**
   * 切换运行函数
   * @param {顺序保持类对象} sequence 
   */
  next(sequence) {
       //执行完毕,关闭定时器
      if (sequence.count == sequence.func_list.length) {
        clearInterval(sequence.timer);
        return;
    }
      if (sequence.running == false) {
          try {
              sequence.running = true;
              //运行下一个函数
              sequence.func_list[sequence.count](sequence);
              sequence.count += 1;
              // 异步执行等待操作
              sequence.wait();
          } catch (error) {
              clearInterval(sequence.timer);
              throw error;
          }
      }
  }
}

Anwendungsbeispiel

let f1 = function (sequence) {
  console.log("f1开始执行");
  setTimeout(function () {
    console.log("f1执行完成");
    sequence.running = false;
    sequence.res=1;
  }, 10)
}
let f2 = function (sequence) {
  console.log("f1执行结果",sequence.res)
  console.log("f2开始执行");
  setTimeout(function () {
    console.log("f2执行完成");
    sequence.running=false;
    sequence.res=2;
  }, 30)
}
let f3 = function (sequence) {
  console.log("f2执行结果",sequence.res)
  console.log("f3开始执行");
  setTimeout(function () {
    console.log("f3执行完成");
    sequence.running=false;
  }, 1)
}
let test = function () {
 let sequence=new SequentialExec([f1,f2,f3]);
 sequence.next(sequence);
}

Führen Sie die Testfunktion aus , um das Ergebnis auszugeben:

 Prinzip

Da das JavaScript- Klassenobjekt als Parameter übergeben wird, handelt es sich um eine flache Kopie (Adresse) . Sie können also das SequentialExec- Objekt als Funktionsparameter verwenden, das laufende Attribut verwenden, um den laufenden Status des asynchronen Vorgangs aufzuzeichnen, und das res- Attribut verwenden Speichern Sie das Ergebnis des asynchronen Vorgangs und verwenden Sie den Zählzähler, um die Ausführungsfunktion zu bestimmen. Hier fungiert die Objektsequenz der SequentialExec- Klasse als Beobachter der Funktion in func_list , d. h. es wird der Beobachtermodus übernommen .

3. Fehlererfassung

Wenn bei mehreren nacheinander ausgeführten Funktionen ein Fehler in einer der Funktionen auftritt, muss die Ausführung einfach durch Ausschalten des Timers beendet werden:

let SequentialExec=class SequentialExec {
  ....
 /**
   * 错误处理
   */
  error(error) {
    clearInterval(this.timer);
    this.running=false;
    console.log("出现错误,终止执行")
    throw error;
  }
  ....
}

Beispielsweise tritt beim Ausführen von f2 ein Fehler auf : 

....
let f2 = function (sequence) {
  console.log("f1执行结果", sequence.res)
  console.log("f2开始执行");
  setTimeout(function () {
    //抛出错误,终止执行
    sequence.error("");
    console.log("f2执行完成");
    sequence.running = false;
    sequence.res = 2;
  }, 30)
}
....

 Ergebnisse der

4. Vorsichtsmaßnahmen

(1) Die obige Methode ist auf Situationen anwendbar, in denen es nur eine asynchrone Funktion unter den Funktionen f1, f2 und f3 gibt .

(2)  sequence.running = false; muss in einer asynchronen Funktion aufgerufen werden , sonst funktioniert die sequentielle Ausführung nicht.

5. Zusammenfassung

Der Vorteil der oben genannten Methode besteht darin, dass sie den Hauptthread nicht blockiert und gleichzeitig die Ausführungsreihenfolge asynchroner Vorgänge beibehält, was für die Datenübertragung in mehreren asynchronen Vorgängen und die Fehlerbehandlung praktisch ist.

Der Nachteil liegt aber auch auf der Hand: Diese Methode ist aufdringlich und generiert eine große Anzahl von sequence.running = false- Aufrufen.

Supongo que te gusta

Origin blog.csdn.net/anbuqi/article/details/122777666
Recomendado
Clasificación