Wątek przeniesiony 2016-07-27 19:13 z Webmastering przez dzek69.

JavaScript - Niedziałająca zmienna

0

Witam, mam taki kod:


function cal_update(cal_akcja)
{
  var ret=false;


  $.post("update.php", { akcja: cal_akcja} , function(data)
  {

    if (data=='ok' || data.length==6 || 1==1) //dodane do testów
    {
      alert(data);
      ret=data;
    }

  });


  return ret;
}

funkcja zawsze zwraca wynik false, mimo, że funkcja post jest wykonana poprawnie, a w alercie wyświetla się poprawnie wynik zwrotny post-u.

Podpowie mi ktoś gdzie popełniłem błąd?

1

Post jest asynchroniczny, funkcja cal_update nie czeka, aż post zostanie wykonany, tylko natychmiast zwraca ret czyli false.

1

Poczytaj o promise'ach :) ewentualnie return daj w bloku tam gdzie masz ajaxa

0

Niestety, asynchroniczność to wrzód na dupie.

Na początek poczytaj o callbackach (funkcja setTimeout jest dobrym przykładem jak działa callback).

Oczywiście, możesz potem korzystać z promisów, które mogą być wygodniejsze od callbacków, ale mają więcej magii koncepcyjnej, więc wydaje mi się, że callbacki są łatwiejsze do ogarnięcia na początek (jeśli chcesz zrozumieć dlaczego tak się dzieje, a nie tylko klepnąć kod i uruchomić).

(zresztą promise'y i tak korzystają z callbacków, po prostu je owijają w magię).

EDIT:
Ponoć w nowej wersji JSa ma się pojawić async i await, które będą ratunkiem na tego typu sytuacje, ale szczerze mówiąc nie wnikałem w to jeszcze.

0

Tak jak przedmówcy napisali, nie załatwisz tego w synchronicznym stylu (no chyba, że użyjesz generatorów lub async-await, ale na to chyba za wcześnie u Ciebie), tu masz przykład na callbackach:

$(function () {
    // główny kod, zamiast zwracać i przypisywać do zmiennej dane z funkcji getData() przygotowujemy dla nich callback,
    // w którym wykonujemy wszystkie potrzebne operacje (będzie on wywołany gdy dane zostaną pobrane):
    getData(function (data) {
      console.log('Pobrane dane:', data);
    });
});

// funkcja z asynchroniczną akcją, przyjmująca callback (dowolną funkcję przyjmującą  w tym wypadku jeden argument z wynikowymi danymi):
function getData(callback) {
  $.get('https://jsonplaceholder.typicode.com/todos/1', function (data) {
    callback(data);
  });
}

CodePen: http://codepen.io/anon/pen/NAzXpZ?editors=0012

Możesz też wykorzystać domknięcie i ustawić wynik jako widoczny dla całego scopa, choć oczywiście nie będzie od razu, dopiero jak wynik zostanie przesłany przez serwer:

$(function () {
  // początkowa wartość danych:
  var mainData = {};

  // przypisanie wynikowych danych do głównej zmiennej
  getData(function (data) {
    mainData = data;
  });
  
  // tu jeszcze nowe dane nie są dostępne, bo wcześniejsze zapytanie nadal się wykonuje,
  // a wykonanie programu poleciało dalej bez blokowania skryptu:
  console.log('mainData tuż po wywołaniu getData():', mainData); // => Object {}
  
  // no ale w pewnym momencie zapytanie w końcu coś zwróci i wartość mainData zostanie zaktualizowana,
  // zasymulujemy to timeoutem:
  setTimeout(function () {
    console.log('mainData po timeoucie:', mainData); // jeśli serwer nie zamuli to powinniśmy zobaczyć już niepusty obiekt
  }, 2000);
});

// funkcja z asynchroniczną akcją, przyjmująca callback (dowolną funkcję przyjmującą  w tym wypadku jeden argument z wynikowymi danymi):
function getData(callback) {
  $.get('https://jsonplaceholder.typicode.com/todos/1', function (data) {
    callback(data);
  });
}

CodePen: http://codepen.io/anon/pen/grKoKd?editors=0012

PS:
Jak chcesz to mogę pokazać też przykład z promisami i generatorami, ale to powinno Ci starczyć na początek - mniej eleganckie i imo mniej czytelne, ale koncepcyjnie prostsze.

0

Panowie, dziękuję za pomocne podpowiedzi, zdecydowanie będą dla mnie drogą do uzupełnienia swojej wiedzy :)

Maciej Cąderek, Googlując sprawę "promisów" dotarłem do funkcji JQuery: $.when jednak nie działa ona w moim przypadku, lub (co bardziej pewne) źle ją stosuję. Czy mógłbym jednak prosić o prosty przykład promisów, na którym trochę poćwiczę tą kwestię?

0

Poczytałem trochę w internetach, natrafiłem na link: http://api.jquery.com/jQuery.ajax/

myślałem, że znajdę tam eleganckie rozwiązanie z async:false, jednak nic z tego, takie ro

związanie niestety też nie działa :(

```javascript
function cal_update(cal_akcja)
{
  var ret=false;


  $.ajax(
  {
    type: 'POST',
    url: 'cal_update.php',
    data: { akcja: cal_akcja },

    complete: function(data)
    {
      ret=data;
    },

    async:false
  });



  return ret;
}
0

Masz tu najprostszy przykład z promise:

$(function () {
    // getData() zwraca promise (detale w opisie funkcji), na której możemy wywołać metodę .then(),
    // do której przekazujemy funkcję przyjmującą wynik promisa i wykonujący na nim potrzebne operacje
    // identycznie jak w wersji z callbackiem,
    // .then() może być wywołane wielokrotnie, może być też wywołane bezpośrednio w funkcji getData(),
    // jęsli byłoby to sensowne - promisa możemy przekazywać dowolnie między funkcjami i "rozpakowywać go"
    // za pomocą .then() tam gdzie potrzebujemy
    getData().then(function (data) {
      console.log(data);
    });
});

// tym razem zwracamy z funkcji od razu wynik dla $.get(), który jest obiektem "promisopodobnym",
// (nie jest to dokładnie promise ze specyfikacji ES6, ale ma bardzo podobne działanie)
function getData() {
  return $.get('https://jsonplaceholder.typicode.com/todos/1');
}

Oczywiście we wszystkich przykładach omijam dla prostoty kwestię obsługi błedów - doczytaj sobie o metodzie .catch() / .fail(). Pomijam też kwestię tworzenia własnych promisów.

PS
Opcja async: false jest bardzo złym rozwiązaniem, niepotrzebnie blokujesz w ten sposób całą stronę na czas trwania zapytania.

0

myślałem, że znajdę tam eleganckie rozwiązanie z async:false,

Tyle, że to nie byłoby eleganckie rozwiązanie, bo w tym momencie byś blokował cały JavaScript na stronie aż do momentu, kiedy się wczyta plik przez AJAX. Innymi słowy - twoja strona by się "zawiesiła" do czasu aż przyszła by odpowiedź z serwera. Nie byłoby to dobre dla użytkownika (brak responsywności).

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