在第一个功能完成后,启动第二个功能。

Start a second function, after the first one has been completed.

我对 jQuery 和 AJAX 有疑问。

我有 2 个函数,做一些 AJAX - 东西:

1:

getSelectedRoom($chosenRoom) 

2:

getDeviceTable("all", "div#DeviceTables",0,1,1,0,1,$chosenRoom)

第一个函数创建 div 并插入图像。现在,完成后,我需要 div 的高度以及里面的图像。因此我需要第二个函数等待,直到第一个函数完成所有操作。

我认为下面的代码可以解决我的问题,但是第二个函数有时会在 div 准备好并获得 0px 高度之前启动。

$.when( 
    // Wohnungsgrundriss anzeigen
    getSelectedRoom($chosenRoom) 

).done(
    // Device Tablle mit allen verfügbaren Geräten füllen.
    getDeviceTable("all", "div#DeviceTables",0,1,1,0,1,$chosenRoom)

);

有没有办法确保在功能 2 开始之前功能 1 已经完成?

下面也是这些函数的代码:

function getSelectedRoom($chosenRoom){
// Ausgewählten Raum mit platzierten Geräten anzeigen
 // Raumgrundriss laden
 $.post("getSelectedRoom.php", {chosenRoom : $chosenRoom},
  function($echoData){
   $("div#SelectedRoom").html($echoData);
   $(".droppable").droppable({
    // Nur Objekte die komplett drin sind werden akzeptiert.
    tolerance: "fit",

    // Funktionsaufruf wenn ein Gerät in das Bild gedropt wird.
    drop: function( event, ui ){
     var $parent = ui.draggable;
     var $draggedElement = $(ui.draggable);
     var $dropZone = $(this);

     // Berechnen der Position relativ zum Zimmergrundriss (als absolute Werte in Px)
     var $leftOffset = $parent.offset().left - $dropZone.offset().left;
     var $topOffset = $dropZone.offset().top - $parent.offset().top;

     // Umrechnen der absoluten Werte zu prozentualen Werten, abhängig vom Zimmergrundriss (Zimmergrundriss = 1000%)
      // Grundrissgröße bestimmen
      var $groundplotWidth = $("div#SelectedRoom").width();
      var $groundplotHeight = $("div#SelectedRoom").height();

      // Umrechnung in %
      $leftOffset = Math.round($leftOffset * ( 1000 / $groundplotWidth ));
      $topOffset = Math.round($topOffset * ( 1000 / $groundplotHeight ));

     //Speichern der Position in der MySQL Tabelle
     $.post("insertDevice.php", {chosenRoom : $chosenRoom, ID : $(ui.draggable).attr('id') , X : $leftOffset, Y : $topOffset},
      function($echoData){
       // Platzhalter für eventuelle Bestätigung nach dem erfolgreichen speichern...
       console.log($echoData);
      });

     // Debugging:
     console.log(".....................");
     console.log(".Einfügen............");
     console.log("chosenRoom: " + $chosenRoom);
     console.log("ID: " + $(ui.draggable).attr('id'));
     console.log("X: " + $leftOffset);
     console.log("Y: " + $topOffset);
     console.log(".....................");

    },
    // Funktionsaufruf wenn ein Gerät aus dem Bild gedropt (war zuvor im Bild) wird.
    out: function( event, ui ){
     $.post("delDevice.php", {chosenRoom : $chosenRoom, ID : $(ui.draggable).attr('id')}, 
      function($echoData){
       // Platzhalter für eventuelle Bestätigung nach dem erfolgreichen löschen...

       // Debugging:
       console.log(".....................");
       console.log(".Entfernen...........");
       console.log("chosenRoom: " + $chosenRoom);
       console.log("ID: " + $(ui.draggable).attr('id'));
       console.log(".....................");
       console.log($echoData);

      });
    }
   });
  });
}

function getDeviceTable($tbl, $target, $splt_id, $splt_zustand, $splt_name, $splt_bedienel, $noText, $chosenRoom){
 if ( $tbl == "all" ) {        // Abfrage für alle Tabellen

  $text =   '<p>Wählen Sie eine Tabelle um die darin enthaltenen Geräte zu bearbeiten.</p>';
  $print =  '<p id="tblCON"></p>' + 
     '<p id="tblFUN"></p>' + 
     '<p id="tblSEN"></p>';
  
  if($noText != 1){   
   $print = $text + $print;
  };

  $($target).html($print);

  // Beide AJAX Calls werden lsogeschickt. then() wird ausgeführt, wenn beide Callbacks durchgeführt wurden.
  $.when(
   getDeviceTable("CONNECTION", "p#tblCON", $splt_id, $splt_zustand, $splt_name, $splt_bedienel, $noText, $chosenRoom),
   getDeviceTable("FUNK", "p#tblFUN", $splt_id, $splt_zustand, $splt_name, $splt_bedienel, $noText, $chosenRoom)
  ).done( positionDevices($chosenRoom) );

  if($noText  != 1){
   getDeviceTable("SENSOR", "p#tblSEN", $splt_id, $splt_zustand, $splt_name, $splt_bedienel); 
  }
  
 } else {           // Abfrage für einzelne Tabelle
  $.post("getDeviceTable.php", {tbl : $tbl, splt_id : $splt_id, splt_zustand : $splt_zustand, splt_name : $splt_name, splt_bedienel : $splt_bedienel, noText : $noText,
  }, function($echoData){
   // Ausgabe der Tabelle im Targetbereich
   if($noText != 1){ 
    if ($tbl == "CONNECTION") {
     $echoData = '<h3>Digitale Ein- & Ausgänge</h3>' + $echoData;
    } else if ($tbl == "FUNK") {
     $echoData = '<h3>Funkschalter & -Steckdosen</h3>' + $echoData;
    } else if ($tbl == "SENSOR") {
     $echoData = '<h3>Temperatursensoren</h3>' + $echoData;
    } else {
     alert("Die Tabelle \"" + $tbl + "\" ist der Funktion getDeviceTable() nicht bekannt!");
    }
   }
   
   if($noText == 1){
   // Ausgabe als aufgeklappte Tabellen
    $($target).html('').append($echoData).fadeOut(0).fadeIn(500);
   // Drag & Drop in der Zimmerverwaltung:
    $(".draggable").draggable({ 
     cancel: false,
     revert: function(event, ui) {
      // jQuery 1.x Version:
      // $(this).data("draggable")
      // jQuery 2.x Version:
      // $(this).data("ui-draggable")
      $(this).data("ui-draggable").originalPosition = {
          top : 0,
          left : 0
      };
      // return boolean
      return !event;
      // Kurzform für: return event !== false ? false : true;
     }
    });
    $(".draggable").css('position','relative');

   }else{
    // Standardausgabe der Tabellen mit Fade Effekt und eingeklappten Tabellen
    $($target).html('').append($echoData).fadeOut(0).ready(hide_all_tr('#'+$tbl,0)).fadeIn(500);
   }
  });
 }
}

function positionDevices($chosenRoom){
// Wenn die Tabellen geladen sind, sollen alle Geräte im Raum an die entsprechende Position geschoben werden.
 // Feststellen welche Geräte im Raum sind!
 $.post("getSelRoomDevices.php", {chosenRoom : $chosenRoom},
  function($echoData){

  // Alle Geräte in $echoData in Position bringen!
   // Debugging
   console.log(".....................");
   console.log(".Laden...............");
   console.log("chosenRoom: " + $chosenRoom);
   console.log($echoData);

   // Tabelle versteckt ausgeben
   $("#hiddenTable").hide().html($echoData);

   // Wie viele Geräte sind in der Tabelle?
   var $anzDevice = $("div#hiddenTable table > tbody > tr").length;

   //Zeile für Zeile auswerten
   for($zeile = 1; $zeile <= $anzDevice; $zeile++){
    // ID & Position auslesen
    $ID = $("div#hiddenTable table > tbody > tr:nth-child(" + $zeile + ") > td:nth-child(1)").html();
    $X  = $("div#hiddenTable table > tbody > tr:nth-child(" + $zeile + ") > td:nth-child(2)").html();
    $Y  = $("div#hiddenTable table > tbody > tr:nth-child(" + $zeile + ") > td:nth-child(3)").html();

    // Debugging
    console.log("ID: " + $ID);
    console.log("X: " + $X);
    console.log("Y: " + $Y);
    console.log("Moved Button ID: button#" + $ID);

    // Grundrissgröße bestimmen
    var $groundplotWidth = $("div#SelectedRoom").width();
    var $groundplotHeight = $("div#SelectedRoom").height();
    $groundplotHeight = $groundplotHeight * (-1);

    // Debugging
    console.log("Grundrissbreite: " + $groundplotWidth + "px");
    console.log("Grundrisshöhe: " + $groundplotHeight + "px");

    // Berechnen der Position in px vom Bildrand
    var $posInsidePicX = ($groundplotWidth / 1000) * $X;
    var $posInsidePicY = ($groundplotHeight / 1000) * $Y * (-1);

    // Debugging
    console.log("Position X des Gerätes im Bild: " + $posInsidePicX + "px");
    console.log("Position Y des Gerätes im Bild: " + $posInsidePicY + "px");

    // Berechnen des Offset des Grundrissbildes:
    var $offsetOfPicX = $("div#SelectedRoom").offset().left;
    var $offsetOfPicY = $("div#SelectedRoom").offset().top;
    $offsetOfPicY = $offsetOfPicY * (-1);

    // Debugging
    console.log("Offset X des Bildes: " + $offsetOfPicX + "px");
    console.log("Offset Y des Bildes: " + $offsetOfPicY + "px");

    // Position im Bild auf Offset des Bildes drauf rechnen um absolute Position zu erhalten
    var $absX = $posInsidePicX + $offsetOfPicX;
    var $absY = $posInsidePicY + $offsetOfPicY;
    $absY = $absY * (-1);

    // Debugging
    console.log("Absolute Position X: " + $absX + "px");
    console.log("Absolute Position Y: " + $absY + "px");

    // Positionieren des Device in die Absolute Position
    $("button#" + $ID).offset({top: $absY, left: $absX});

    // Debugging
    console.log(".....................");
   }

   // Debugging
   console.log("Anzahl enthaltener Geräte: " + $anzDevice);
   console.log(".....................");
  });
}

您的代码有几个问题:

首先,正如我在评论中解释的那样,$.when() 没有神奇的力量,如果您向它传递一个或多个承诺,它只能在异步操作完成时通知您。您将 getSelectedRoom() 的 return 结果传递给它,即 undefined 所以 $.when() 没有传递承诺,因此只是调用它的 .done() 处理程序立即地。而且,一旦你 return 得到 getSelectedRoom() 的承诺,你根本不需要使用 $.when() 因为你只有一个承诺,你可以只使用 .then() 直接上。 $.when() 仅在您有多个 promise 并且您想知道它们何时全部完成时才用于通知异步完成。

只需更改以下内容即可轻松解决此问题:

function getSelectedRoom($chosenRoom){
// Ausgewählten Raum mit platzierten Geräten anzeigen
    // Raumgrundriss laden
    $.post("getSelectedRoom.php", {chosenRoom : $chosenRoom},
    ....
}

对此:

function getSelectedRoom($chosenRoom){
// Ausgewählten Raum mit platzierten Geräten anzeigen
    // Raumgrundriss laden
    return $.post("getSelectedRoom.php", {chosenRoom : $chosenRoom},
    ....
}

现在,您正在 returnjQuery ajax $.post()getSelectedRoom() 的承诺,所以现在可以这样做了:

getSelectedRoom(...).then(function() {
    getDeviceTable("all", "div#DeviceTables",0,1,1,0,1,$chosenRoom);

});

其次,如果您尝试测量刚刚插入的某些 HTML 的大小,这可能会或可能不会工作,因为浏览器可能还没有完成 layout/repaint (重绘是否发生将取决于 promise 库的一些实现细节)。您可以通过这样做来保证重绘已经发生:

getSelectedRoom(...).then(function() {
    setTimeout(function() {
        getDeviceTable("all", "div#DeviceTables",0,1,1,0,1,$chosenRoom);
    }, 1);
});