Zatrzymanie metody do czasu wykonania akcji

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.

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?

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;
},
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(...).

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

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ść

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:

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

a potem:

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)

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).

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ść.

1 użytkowników online, w tym zalogowanych: 0, gości: 1