• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Okiełznanie asynchroniczności w JavaScript.

VPS Starter Arubacloud
0 głosów
358 wizyt
pytanie zadane 23 sierpnia 2018 w JavaScript przez CP733 Początkujący (390 p.)

Witajcie, od dłuższego czasu nie mogę sobie poradzić z wydaje się prostą rzeczą.
 

function example() {
    var msg = '';
    var arr = ['jeden', 'dwa', 'trzy'];
    
    arr.forEach(value => {
        setTimeout(() => {
            
            msg += value;
        
        }, 2000)
    })
    
    console.log(msg);
}

example();


Tak w wielkim uproszczenia wygląda moja prawdziwa funkcja. Nie mam pomysłu jak wykonać console.log(msg); po całym przypisaniu tych wartości do zmiennej msg. Chodzi mi o dokładnie ten przykład, nie szukam innego sposobu, tylko pomocy z opanowaniem asynchroniczności.

4 odpowiedzi

+1 głos
odpowiedź 23 sierpnia 2018 przez Comandeer Guru (599,730 p.)
wybrane 23 sierpnia 2018 przez CP733
 
Najlepsza

Ja bym sobie zrobił dodatkową zmienną, i, która na końcu każdego setTimeout byłaby inkrementowana. I w chwili, gdy ta zmienna osiągnie wartość równą długości tablicy arr – odpalam console.log (oczywiście wciąż wewnątrz setTimeout).

+1 głos
odpowiedź 23 sierpnia 2018 przez pablop76 VIP (123,060 p.)
Umieść console.log wewnątrz setTimeout, lub w funkcji, którą wywołaj w setTimeout.

Kod js wykonuje się od góry do dołu, ale setTimeout jest funkcją asynchroniczną, więc nie podlega tej zasadzie. I gdy prubujesz wyświetlić msg ta zmienna jeszcze nie została zmieniona Program nie wie czy setTimeout zakończyła działanie.
+1 głos
odpowiedź 23 sierpnia 2018 przez Trisoft Początkujący (490 p.)

ja bym to zrobił np. tak 

function example() {
    var msg = '';
    var arr = ['jeden', 'dwa', 'trzy'];
     
    arr.forEach((value, index, array )=> {
        setTimeout(() => {
             
            msg += value;
            if(index === array.length-1){
         			console.log(msg);   
            }
         
        }, 2000)
    })
}
 
example();

bardzo proste rozwiązanie ale działa :)

0 głosów
odpowiedź 23 sierpnia 2018 przez CP733 Początkujący (390 p.)
Dzięki, nie wpadłem na tak proste rozwiązanie. Mam jeszcze jedno pytanie, w forEach mam funkcje axiosa, która pobiera i przetwarza dane ze strony, ale zapętlanie jest tak szybkie, że po prostu wyskakują errory 503, dlatego też użyłem setTimeout. Istnieje jakiś lepszy sposób? Niestety, ale z używaniem tego setTimeout wiąże się mnóstwo przykrości.
komentarz 23 sierpnia 2018 przez Trisoft Początkujący (490 p.)
Może spróbuj rozwiązać to rekurencją zamiast forEach.

Jesteś w stanie podesłać kod jak to wygląda dokładnie.
komentarz 23 sierpnia 2018 przez CP733 Początkujący (390 p.)
    getGroupEarnings(groupName, message, countOfEmployees) {

        var employees = this.employeeList;
        var messageToDelete;

        message.reply('daj mi chwilkę.').then((msg) => {
            messageToDelete = msg;
        });

        var groupSum = 0;
        var msg = '**'+groupName+'**: ';
        var i = 1;
        employees.forEach((value, index) => {
            setTimeout(() => {
                if (value.team == groupName) {
                    var url = 'strona'+value.uid;
                    axios(url, {
                        headers: {
                            cookie: [
                                cookie.serialize('', ''),
                                cookie.serialize('', ''),
                                cookie.serialize('', '')
                            ].join(';')
                        }
                    }).then(response => {
                        const regex = /(?=.\)\$(.*?) -)(?=.*<br \/><span class="desc">(.*?)<\/span><\/td>)/g;
                        const body = response.data;

                        let m;
                        var sum = 0;
                        while ((m = regex.exec(body)) !== null) {
                            
                            if (m.index === regex.lastIndex) {
                                regex.lastIndex++;
                            }
                            
                            m.shift();

                            if (m[1].includes('dziś')) {
                                var offerDate = new Date();
                            offerDate.setHours(18)
                            offerDate.setMinutes(0)
                            offerDate.setSeconds(0)
                            } else if (m[1].includes('wczoraj')) {
                                var offerDate = new Date();
                            offerDate.setDate(offerDate.getDate() - 1)
                            offerDate.setHours(18)
                            offerDate.setMinutes(0)
                            offerDate.setSeconds(0)
                            } else {
                                var offerDateString = m[1].replace('-18', '-2018').replace( /(\d{2})-(\d{2})-(\d{4})/, "$2-$1-$3");
                                var offerDate = new Date(offerDateString);
                            offerDate.setHours(18)
                            offerDate.setMinutes(0)
                            offerDate.setSeconds(0)
                            }

                            var sunday = new Date();
                            var day = sunday.getDay();
                            sunday.setDate(sunday.getDate() - day);
                            var fullDate = sunday.getDate() + '-' + sunday.getMonth() + '-' + sunday.getFullYear();


                            if (offerDate <= sunday) { 
                                break;
                            } else {
                                sum += parseInt(m[0]);
                            }
                        }
                        groupSum += sum;
                        msg += 'dsa';
                        
                        if (i == countOfEmployees) {
                            messageToDelete.delete();
                            message.reply('asd');
                            message.reply(msg);
                        }

                        i++;

                    }).catch(error => {
                        message.reply('wystąpił error!');
                        console.log(error);
                    })
                }
            }, 1000 * index)
            })

    }



Chodzi ogólnie o bota na discorda, oprócz wcześniejszego pytania mam jeszcze jedno.

Jak tutaj sobie poradzić z asynchronicznością?

 

client.on('message', async message => {
		let args = message.content.split(/ +/);
		switch (args[0]) {
      
			case '/cmd':
              
              const singleCounter = new singleCounterCommand();
              singleCounter.getGroupEarnings(groupName, message, countOfEmployees);
              break;
        }
});

Obiekt singleCounter tworzy się za późno po prostu.

komentarz 23 sierpnia 2018 przez Trisoft Początkujący (490 p.)

jeżeli chodzi o pierwszy to spróbuj z async await, tutaj masz taka funkcje która może ci rozjasni o co mi chodzi:

function x(){
  const e = [1,2,3,4,5];
  
  e.forEach(async d=>{
    const resolve = await fetch(`https://jsonplaceholder.typicode.com/todos/${d}`);
    const json = await resolve.json();
    console.log(json)
  })
  
}

x()

a w drugim przypadku nie wiem zbytnio o co chodzi, bo używasz niby async ale nigdzie nie ma await

komentarz 23 sierpnia 2018 przez CP733 Początkujący (390 p.)
No właśnie bo próbuję w różne sposoby użyć await, ale żaden nie działa, zawsze funkcja próbuje wykonać się przed stworzeniem obiektu.
komentarz 24 sierpnia 2018 przez Trisoft Początkujący (490 p.)
Może zacznijmy od początku, co to znaczy że obiekt singleCounter tworzy się za późno w kontekście twojej funkcji ?
komentarz 24 sierpnia 2018 przez CP733 Początkujący (390 p.)

Oznacza to, że próbuje się wykonać pierwsza ta linijka

singleCounter.getGroupEarnings(groupName, message, countOfEmployees);

Co oczywiście zwraca błąd bo skoro obiekt się jeszcze nie stworzył, no to nie można się odwołać do metody.

Podobne pytania

0 głosów
1 odpowiedź 479 wizyt
pytanie zadane 18 stycznia 2021 w JavaScript przez antypop Mądrala (5,730 p.)
0 głosów
1 odpowiedź 201 wizyt
0 głosów
2 odpowiedzi 632 wizyt
pytanie zadane 18 sierpnia 2021 w JavaScript przez adek236 Nowicjusz (180 p.)

92,454 zapytań

141,262 odpowiedzi

319,089 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...