Zatrzymanie metody do czasu wykonania akcji

Zatrzymanie metody do czasu wykonania akcji
G1
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 507
0

Witam serdecznie. Mam akcję zdarzenia dragStop. Podczas zmiany grupy z A na B muszę sprawdzić w bazie danych, czy ta akcja może być faktycznie wykonana. Jeżeli nie, to musze ustawić args.cancel = true.

Kopiuj
dragStop: async function (args) {
    var vehicleId = args.data[0];
    var targetGroup = args.data[0].groupId;

    var isCanceled = true;

    const waitFunction = async () => {
        while (!isFinished)
            continue;
    }

    _vehiclesService
        .getVehicleForEdit(vehicleId)
        .done(function (data) {
            isCanceled = !data.canChangeData;
        });
    args.cancel = isCanceled;
},

Problem polega na tym, że funkcja zostaje wykonana i zwraca args.cancel = true zanim wykona się metoda serwisu _vehiclesService. Serwisu nie mogę zmienić aby ustawić go jako synchroniczny, a muszę w jakikolwiek sposób poczekać na wykonanie akcji. Próbowałem też w sposób poniżej, ale zwiesza mi przeglądarkę. Macie jakieś wskazówki?

Kopiuj
dragStop: async function (args) {
    var vehicleId = args.data[0];
    var targetGroup = args.data[0].groupId;

    var isCanceled = true;
    var isFinished = false;

    const waitFunction = async () => {
        while (!isFinished)
            continue;
    }

    var getForEitData = _vehiclesService
        .getVehicleForEdit(vehicleId)
        .done(function (data) {
            isCanceled = false;
        });
    getForEitData.then(function () {
        isFinished = true;
    })
    await waitFunction();
    args.cancel = isCanceled;
},
SW
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 250
1

JS jest zasadniczo jednowątkowy z Event Loop, więc Twój while blokuje wykonanie kodu. Co możesz zrobić? Przykłado przed wywołaniem serwisu możesz ustawić zmienną, że request poszedł, i dla jakiego obiektu, sprawdzać ją tam gdzie potrzebujesz, a po odpowiedzi z serwisu dalej wykonać logikę.

Czyli agrs i inne zmienne ustawiasz w callbacku then(...).

ZD
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 2310
2
SkrzydlatyWąż napisał(a):

JS jest zasadniczo jednowątkowy z Event Loop

Język nie jest jednowątkowy, ani nie specjalnie wielowątkowy (... jak jakieś Erlangi czy nie wiem co)
Jednowątkowe jest jego główne użycie w przeglądarce o architekturze jak mówisz

Akurat kiedyś obcowałem ze środowiskiem pozaprzeglądarkowym, obcując z gołym językiem, ale bez DOM, onClicków
Wygrały inne interpretery

G1
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 507
0

Czyli nic się nie da zrobić z tym callbackiem przed przeniesieniem karty w kanban? W przypadku niepowodzenia muszę w callback ustawić cancel na true. Aktualnie obszedłem to, ale fajnie będzie wiedzieć na przyszłość

LukeJL
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 8488
1

Pomieszały ci się poziomy abstrakcji.

Async/await jest cukrem składniowym na obiekty Promise. Promisy z kolei są cukrem składniowym na callbacki (w zasadzie nie tylko, bo wprowadzają abstrakcję przyszłej wartości. Tym niemniej i tak, żeby korzystać z promisów, to podajesz callback do metody .then (chyba, że używasz async/await), plus robiąc swojego Promise (new Promise) dostajesz callbacki resolve i reject więc można uznać promisy w pewien sposób za coś, co opakowuje callbacki).
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Czyli:

  1. najniższy poziom abstrakcji: callbacki
  2. promisy: opakowują callback i stanowią abstrakcję przyszłej wartości
  3. async-await cukier składniowy na promisy. Piszemy w sposób, który pozwala czekać na promisy bez użycia callbacków

I teraz. Chcesz używać wysokiego poziomu abstrakcji async/await (czyli promisów pod spodem), jednak wywołujesz w środku metodę _vehiclesService.getVehicleForEdit, która używa callbacków, czyli niskiego poziomu abstrakcji.

Jednak próbujesz pisać jednocześnie na async-await, promisach i callbackach bez konwersji między tymi podejściami...

Co możesz zrobić?

np. zrefaktorować _vehiclesService.getVehicleForEdit, żeby była zgodna z paradygmatem promisów/async-await.

Ale możesz też zostawić _vehiclesService.getVehicleForEdit w spokoju i samemu opakować sobie to w Promise:

Kopiuj
function getForEitData() {
   return new Promise(resolve => {
      _vehiclesService.getVehicleForEdit(vehicleId)
      .done(function (data) {
          resolve({ isCanceled: !data.canChangeData }); 
       }).then(function () {
           resolve({ isFinished: true }); 
       })
   
   });
}

a potem:

Kopiuj
const result = await getForEitData();

(Swoją drogą to już jest jakiś promiso-podobny obiekt, skoro masz metodę then. No ale tam masz metodę done jeszcze. W sumie nie wiem, co tam masz w tym API)

Kopiuj
var isCanceled = true;

BTW nie ma powodu, żeby używać w takim przypadku var. proponuję przesiąść się całkowicie na const i let (doczytasz sobie, dlaczego).

G1
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 507
0

@LukeJL dziękuję Tobie za to wyjaśnienie. Zanim to zastosuję (lub spróbuję zastosować) będę musiał przeanalizować to, co napisałeś więc proszę o trochę czasu :) JS'a uczyłem się znając c# i rozwiązując wszystkie "przypadki" na bieżąco. To co napisałeś to dla mnie całkowita nowość.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.