znaczacy > comp.lang.* > comp.lang.javascript

Roman Tyczka (07.08.2018, 16:35)
Witam,

Moje boje z JS utknely na tym, ze liczenie haszy w bibliotece standardowej
jest asynchroniczne i calosc rozbija sie o obiekt typu Promise zwracany z
metody digest().
Czytam o tym nieszczesnym Promise i nie ogarniam.
Chcialbym poczekac az w tle zostanie policzony czas, wiec na koncu funkcji
haszujacej dopisuje:

Promise.race([hash_promise]).then(function (value) {
haszyk = value;
});
return haszyk;

spodziewajac sie, ze race() bedzie czekac, tymczasem race() przechodzi bez
zatrzymania, mimo, ze hash_promise nadal jest pending i do return trafia
pusty string haszyk, bo go nikt nie wypelnil.

Jak zmusic JS, zeby czekal az asynchroniczne zadanie bedzie wykonane?
Borys Pogorelo (08.08.2018, 22:29)
Dnia Tue, 7 Aug 2018 16:35:54 +0200, Roman Tyczka napisal(a):

> spodziewajac sie, ze race() bedzie czekac, tymczasem race() przechodzi bez
> zatrzymania, mimo, ze hash_promise nadal jest pending i do return trafia
> pusty string haszyk, bo go nikt nie wypelnil.


Nie wkleiles calego kodu, ale czy przypadkiem nie zwracasz zmiennej
"haszyk" od razu? Ona zostanie zmieniona dopiero gdy Promise sie rozwiaze.

I generalnie Promise.race() nie do tego sluzy. To stosunkowo rzadko
potrzebne narzedzie, które czeka na wynik jednej z wielu promises. Niby
mozna by tego uzyc w zaproponowany przez Ciebie sposób, ale jest to
kompletnie zbedne. Wystarczy sie od razu odwolac do obiektu.

> Jak zmusic JS, zeby czekal az asynchroniczne zadanie bedzie wykonane?


Nie zmusisz. Musisz myslec asynchronicznie - kod operujacy na wyniku
funkcji haszujacej musi poczekac na wynik Promise:

Roman Tyczka (08.08.2018, 23:34)
On Wed, 8 Aug 2018 22:29:26 +0200, Borys Pogorelo wrote:

> Dnia Tue, 7 Aug 2018 16:35:54 +0200, Roman Tyczka napisal(a):
> Nie wkleiles calego kodu, ale czy przypadkiem nie zwracasz zmiennej
> "haszyk" od razu? Ona zostanie zmieniona dopiero gdy Promise sie rozwiaze.
> I generalnie Promise.race() nie do tego sluzy. To stosunkowo rzadko
> potrzebne narzedzie, które czeka na wynik jednej z wielu promises. Niby
> mozna by tego uzyc w zaproponowany przez Ciebie sposób, ale jest to
> kompletnie zbedne. Wystarczy sie od razu odwolac do obiektu.
> Nie zmusisz. Musisz myslec asynchronicznie - kod operujacy na wyniku
> funkcji haszujacej musi poczekac na wynik Promise:
>


Powiedzmy, ze rozumiem jako tako jak to dziala, jest to dosc sprytne.
Tylko, ze teraz jest problem. Mam kod, który wywoluje pod buttonem, to
klasyczny kod sekwencyjny. Linia po linii zbiera dane, laczy stringi, liczy
hasze, cos tam jeszcze robi i na koncu wrzuca wynik do jakiegos
pola/zmiennej. I jesli teraz jedna potrzebna funkcja czyli hasz narzuca mi
styl asynchroniczny to zmusza do przeorania calego kodu na ten model i
wolania wszystkiego w kolejnych promisach i then'ach. Pewnie, ze to fajne,
elastyczne i generalnie lepsze, ale sa sytuacje gdy nie chce przerabiac
kodu do tej wymuszonej asynchronicznosci, co wtedy?

Przykladowo mam stary kod:

value = valueX + valuY + SHA512(valueZ);
value = cryptoAES(value);

Prosta rzecz. A teraz musze ten caly kod zawijac w, skadinnad uzyteczne,
ale wygibasy, promisów.

Czy moge jakos wymusic synchronicznosc? Próbowalem z tym async/await ale to
nie zadzialalo. Moze cos zle robilem, a moze to musi byc nowsza
przegladarka.

ps. dlaczego w ogóle ten modul crypto wsadzili w Promise? Z powodu
zlozonosci obliczeniowej i realnie dlugiego czasu wykonania?
Borys Pogorelo (10.08.2018, 11:53)
Dnia Wed, 8 Aug 2018 23:34:09 +0200, Roman Tyczka napisal(a):

> I jesli teraz jedna potrzebna funkcja czyli hasz narzuca mi
> styl asynchroniczny to zmusza do przeorania calego kodu na ten model i
> wolania wszystkiego w kolejnych promisach i then'ach. Pewnie, ze to fajne,
> elastyczne i generalnie lepsze, ale sa sytuacje gdy nie chce przerabiac
> kodu do tej wymuszonej asynchronicznosci, co wtedy?


Wtedy masz problem ;)

Niestety kod asynchroniczny wymaga innej budowy i uwzglednienia tego, ze
trzeba czekac na wynik. Nawet tylko jeden cykl CPU, ale trzeba.

> Czy moge jakos wymusic synchronicznosc? Próbowalem z tym async/await ale to
> nie zadzialalo. Moze cos zle robilem, a moze to musi byc nowsza
> przegladarka.


To i to. W drugim watku wrzucilem przyklad.

> ps. dlaczego w ogóle ten modul crypto wsadzili w Promise? Z powodu
> zlozonosci obliczeniowej i realnie dlugiego czasu wykonania?


Tak. Wszelkie operacje synchroniczne blokuja event loop.
Roman Tyczka (10.08.2018, 12:49)
On Fri, 10 Aug 2018 11:53:03 +0200, Borys Pogorelo wrote:

> Wtedy masz problem ;)
> Niestety kod asynchroniczny wymaga innej budowy i uwzglednienia tego, ze
> trzeba czekac na wynik. Nawet tylko jeden cykl CPU, ale trzeba.


[...]

>> ps. dlaczego w ogóle ten modul crypto wsadzili w Promise? Z powodu
>> zlozonosci obliczeniowej i realnie dlugiego czasu wykonania?

> Tak. Wszelkie operacje synchroniczne blokuja event loop.


Powiedz mi jak to w ogóle dziala pod spodem, skoro JS jest niby
jednowatkowy? Jak przerwania w epoce DOSa na PC AT?
Cezary Tomczyk (10.08.2018, 16:22)
On 10/08/2018 12:53, Borys Pogorelo wrote:
> Dnia Wed, 8 Aug 2018 23:34:09 +0200, Roman Tyczka napisal(a): [...]
>> ps. dlaczego w ogóle ten modul crypto wsadzili w Promise? Z powodu
>> zlozonosci obliczeniowej i realnie dlugiego czasu wykonania?

> Tak. Wszelkie operacje synchroniczne blokuja event loop.


Garsc o tym:
Roman Tyczka (10.08.2018, 18:19)
On Fri, 10 Aug 2018 17:22:02 +0300, Cezary Tomczyk wrote:

> On 10/08/2018 12:53, Borys Pogorelo wrote:
> [...]
> Garsc o tym:
>


To nie wyjasnia wszystkiego, bo uzyty zostal fatalny przyklad z tym
setTimeout(). Czekanie 2 sekundy nic nie kosztuje. I jest latwe do
implementacji tak jak to opisano.
Ale co z sytuacja, gdy funkcja asynchroniczna robi cos "grubego" w tle, jak
chocby to liczenie hasza?
Czy wtedy:
a) jest oczekiwanie na pustego call stacka i wrzucenie calego "grubego"
zadania do wykonania (tak wynika z artykulu)?
b) czy moze to poboczne zadanie jest dzielone na fragmenciki i wywolywane
po kawalku w wolnych chwilach (tak jak w aplikacjach z prawdziwa
wielowatkowoscia)?

Druga opcja ma wiekszy sens, ale jest duzo trudniejsza w implementacji.
Zatem nadal nie wiem czy wiem co sie tam tak naprawde dzieje :-)

Zwlaszcza, ze autor arta sam pisze na koncu:

"I don’t know how accurately I am able to demonstrate this topic but there
are a lot in between that could have been elaborated or explained better,
but am in a rush and it’s already too long already. Hope it helps someone."

ps. W Delphi (jesli mowa o programowaniu bez watków) tez istnieje cos
takiego jak timer i tez mozna mu zapodac zrobienie czegos za okreslony czas
i dziala to tak jak opisano w tym artykule, czyli petla komunikatów dostaje
komunikat WM_TIMER i adres procedury obslugi, która wywoluje jesli nie jest
akurat niczym zajeta. To dosc uboga "asynchronicznosc", ale czasami
wystarcza. Gdyby jednak procedura spod timera byla dlugotrwala to petla
komunikatów zostanie zablokowana i aplikacja przestanie odpowiadac (czesto
to widac w zle napisanych aplikacjach, gdy GUI przestaje sie rysowac i nie
dzialaja kontrolki).
Borys Pogorelo (10.08.2018, 22:31)
Dnia Fri, 10 Aug 2018 18:19:58 +0200, Roman Tyczka napisal(a):

> Ale co z sytuacja, gdy funkcja asynchroniczna robi cos "grubego" w tle, jak
> chocby to liczenie hasza?
> Czy wtedy:
> a) jest oczekiwanie na pustego call stacka i wrzucenie calego "grubego"
> zadania do wykonania (tak wynika z artykulu)?


Cale zadanie. Jednowatkowosc do bólu (pominawszy webworkery). Dlatego warto
jak najbardziej kroic skomplikowany kod.

> wystarcza. Gdyby jednak procedura spod timera byla dlugotrwala to petla
> komunikatów zostanie zablokowana i aplikacja przestanie odpowiadac (czesto
> to widac w zle napisanych aplikacjach, gdy GUI przestaje sie rysowac i nie
> dzialaja kontrolki).


Javascriptem tez zablokujesz UI, jesli odpalisz cos "ciezkiego".
Podobne w±tki