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

42 Warsaw Coding Academy
0 głosów
579 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 (607,060 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,540 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ź 744 wizyt
pytanie zadane 18 stycznia 2021 w JavaScript przez antypop Mądrala (5,730 p.)
0 głosów
1 odpowiedź 439 wizyt
0 głosów
2 odpowiedzi 1,298 wizyt
pytanie zadane 18 sierpnia 2021 w JavaScript przez adek236 Nowicjusz (180 p.)

93,394 zapytań

142,387 odpowiedzi

322,550 komentarzy

62,752 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

VMware Cloud PRO - przenieś swoją infrastrukturę IT do chmury
...