Rozszerzenie Promise o niestandardowe funkcje mutexowe

0

Mamy oto definicje:

Promise.prototype.DodatkiSkryptThen=function(...args){
    return jQuery.fn.DodatkiSkryptReady(function(){
    	var promise=generowane_watki.wygeneruj(1);
    	var wynik=this.then(...args);
    	return Promise.allSettled([promise,wynik]).then(function(){//1
        	generowane_watki.zwolnij();
    		return wynik;
    	});
     });
}
Promise.prototype.DodatkiSkryptCatch=function(...args){
    return jQuery.fn.DodatkiSkryptReady(function(){
    	var promise=generowane_watki.wygeneruj(1);
    	var wynik=this.catch(...args);
    	return Promise.allSettled([promise,wynik]).then(function(){//2
        	generowane_watki.zwolnij();
    		return wynik;
    	});
    });
}
/*A wywołanie*/
var promise=new Promise(function(resolve,reject){
  resolve();
});
promise.DodatkiSkryptThen(function(data){...}).DodatkiSkryptCatch(function(data){...});

Metody funkcji: generowane_watki, same się odblokowują, więc z tą funkcją nie ma problemów. Funkcja: jQuery.fn.DodatkiSkryptReady, to funkcja z licznikiem kontrolowana przez pewny jeden muteks. Z licznikami tam raczej nie ma problemów. Jak zauważyłem funkcja się blokuje na linii:

return Promise.allSettled([promise,wynik]).then(function(){

i nie che iść dalej, tak jak by obietnica: wynik, by się nie zwalniała, funkcja, tam, jak sprawdzałem,. .then, oczekuje na wynik: "<state>:pedding". Ten problem widocznie występuje, kiedy obietnice się zwolniły z dyrektywą: resolve, ale nigdy: reject, i pewnie dlatego obietnica zwracana przez: this.then nie blokuje się, a: this.catch, już się blokują. Pytanie: Jak ten problem naprawić?

2

Ale w zasadzie po co Ci tutaj mutexy, skoro JS jest jednowątkowy?

(btw, pls - 🙏 - pisz kod po angielsku)

0
Patryk27 napisał(a):

Ale w zasadzie po co Ci tutaj mutexy, skoro JS jest jednowątkowy?

(btw, pls - 🙏 - pisz kod po angielsku)

Mamy sobie funkcje muteksu: .zablokuj() i .odblokuj(), funkcja .zablokuj() zwraca pewną obietnicę, która zawsze zwraca resolve(), a więc to działa jak wątek. Mamy kod:

var muteks=new Muteks();
muteks.zablokuj().then(function(data){
  /*Jakiś kod numer 1*/
  muteks.odblokuj();
});
muteks.zablokuj().then(function(data){
  /*Jakiś kod numer 2*/
  muteks.odblokuj();
});

I dlatego chcę zaimplementować funkcje: .DodatkiSkryptThen i .DodatkiSkryptCatch, o muteksy.
Więc ponawiam pytanie z tego wątku.

0

[...] a więc to działa jak wątek.

Huh, co tutaj działa jak wątek?

I dlatego [...]

Niestety nie rozumiem - dlaczego i po co? (ale tak powoli)

0
Patryk27 napisał(a):

[...] a więc to działa jak wątek.

Huh, co tutaj działa jak wątek?

I dlatego [...]

Niestety nie rozumiem - dlaczego i po co? (ale tak powoli)

Jak mamy kilka obietnic, z pewnymi modyfikacjami w nich pewnej zmiennej, a w nim muteksu można sposodować, że jakaś zmienna jest tylko w danym momencie jest modyfikowana tylko raz. Funkcję: .zablokuj(), można tak zdefiniować:

function Muteks(){
  /*Jakiś kod wstępny*/
  this.zablokuj=function(){
    return new Promise(function(resolve,reject){
      /*Tutaj w pewnym momencie jest wywołana instrukcja: resolve()*/
    });
  }
}

Tutaj działa wykonywanie funkcji we wnętrzu Promise jak wątek, funkcja we wnętrzu .then zostanie wykonana, kiedy kod we wnętrzu Promise zostanie wykonany do końca, ze zwróconym wynikiem resolve(). Może obietnica: var promise=muteks.zablokuj() jest synchroniczna, ale wykonywanie jej metod jest asynchroniczne, tzn. funkcja we wnętrzu .then, nie wiadomo kiedy zostanie wykonana, ale zostanie wykonana, nawet może się wykonać po dziesięciu sekundach po wykonaniu głównego wątku synchronicznego.

1

Zmienna zawsze będzie modyfikowana tylko raz, jak callbacki schodzą z event loop. Taka jest koncepcja działania JS. Trudno z opisu zrozumieć Twoją koncepcję. Czy Tobie nie chodzi bardziej o to, żeby wywołania Promise w jakiś sposób kolejkować? W jakim celu?

0
SkrzydlatyWąż napisał(a):

Zmienna zawsze będzie modyfikowana tylko raz, jak callbacki schodzą z event loop. Taka jest koncepcja działania JS. Trudno z opisu zrozumieć Twoją koncepcję. Czy Tobie nie chodzi bardziej o to, żeby wywołania Promise w jakiś sposób kolejkować? W jakim celu?

Kiedyś, jak nie stosowałem muteksów, to przeglądarka, nawet się zawieszała, i trzeba było na siłę ją wyłączać. Chodzi mi pewne kolejkowanie pewnych Promise w grupy, każda byłaby oprawiona w pewny muteks, każda grupa jest kontrolowana przez inny muteks, chodzi tutaj o pewne operacje wykonywane jedna po drugiej, aby kod się nie zawiesił.

4

Tutaj działa wykonywanie funkcji we wnętrzu Promise jak wątek

Nie, bo wątek implikuje możliwość wykonywania kodu równolegle, podczas gdy promisy w JSie są przykładem cooperative multitaskingu, tutaj w szczególności w oparciu o event loop. Nawet jak zakolejkujesz sto promisów, w danej chwili zawsze wykonywany będzie najwyżej jeden.

Nie wiem dlaczego Twój kod blokuje przeglądarkę i nie rozumiem w jaki sposób manualna implementacja mutexa miałaby tutaj pomóc - może po prostu wrzuć ten kod, który powoduje zawieszenie przeglądarki i to jemu się przyjrzymy?

0
Patryk27 napisał(a):

Tutaj działa wykonywanie funkcji we wnętrzu Promise jak wątek

Nie, bo wątek implikuje możliwość wykonywania kodu równolegle, podczas gdy promisy w JSie są przykładem cooperative multitaskingu, tutaj w szczególności w oparciu o event loop. Nawet jak zakolejkujesz sto promisów, w danej chwili zawsze wykonywany będzie najwyżej jeden.

Nie wiem dlaczego Twój kod blokuje przeglądarkę i nie rozumiem w jaki sposób manualna implementacja mutexa miałaby tutaj pomóc - może po prostu wrzuć ten kod, który powoduje zawieszenie przeglądarki i to jemu się przyjrzymy?

Może instrukcja dana w JS jest wykonywana jest tylko ona w danym momencie w jednowątkowym procesie, ale jak kod w funkcji we wnętrzu Promise ma wiele instrukcji,tzn. new Promise(function(resolve,reject){/*Tutaj chodzi o ten kod*/}); to co wtedy, wtedy ma wiele mniejszych instrukcji, czyli jak w takim przypadku, przecież ta obietnica ma we wnętrzu funkcję z wieloma instrukcjami. A chrome jest wielowątkową, a inne jednowątkowymi, przeglądarkami.

A nie lepiej normalny wątek nazwać synchroniczny, a jak w JS asynchrorniczny. Kiedyś przeglądarka się zawiesiała na firefoksie, a teraz już tak nie robi, to raczej wynika z jej wersji.

4

czyli jak w takim przypadku, przecież ta obietnica ma we wnętrzu funkcję z wieloma instrukcjami

Dokładnie tak samo, nadal wykonywana jest tylko - powiedzmy - "jedna linijka kodu JSa" w danej chwili; jeśli utworzysz sto promisów, każdy z nich będzie wykonywał się jeden po drugim, a nie jednocześnie.

W szczególności jeśli zespawnujesz Promise w którym zrobisz while (true) {}, to tak czy siak zablokujesz całą przeglądarkę (albo przynajmniej całą kartę) oraz wszytkie inne Promise'y (a przynajmniej te w danej karcie).

A nie lepiej normalny wątek nazwać synchroniczny, a jak w JS asynchrorniczny.

Nie ma tutaj żadnych wątków whatsoever; poczytaj sobie o event loop w JSie.

0
Patryk27 napisał(a):

czyli jak w takim przypadku, przecież ta obietnica ma we wnętrzu funkcję z wieloma instrukcjami

Dokładnie tak samo, nadal wykonywana jest tylko - powiedzmy - "jedna linijka kodu JSa" w danej chwili; jeśli utworzysz sto promisów, każdy z nich będzie wykonywał się jeden po drugim, a nie jednocześnie.

W szczególności jeśli zespawnujesz Promise w którym zrobisz while (true) {}, to zablokujesz całą przeglądarkę (albo przynajmniej całą kartę) oraz wszytkie inne Promise'y (a przynajmniej te w danej karcie).

A nie lepiej normalny wątek nazwać synchroniczny, a jak w JS asynchrorniczny.

Nie ma tutaj żadnych wątków whatsoever; poczytaj sobie o event loop w JSie.

Może obietnica: new Promise, jako instrukcja, jest wykonywana tylko ona w danym momencie, ale ona wywołuje funkcję z wieloma instrukcjami, czy te funkcje są wykonywane po kolei, czy instrukcja po instrukcji.

Jak mamy kod:

promise.DodatkiSkryptThen(function(data){}).DodatkiSkryptCatch(function(data){});

to zauważ, że kod we wnętrzu, tutaj: function(data){}, w funkcji: .DodatkiSkryptThen, zostanie wykonany, i jego obietnica zostanie rozwinięta, a w: .DodatkiSkryptCatch, już nie, i dlatego: wynik=this.then, nie blokuje, a wynik=this.catch blokuje, jeśli wynik wstawimy do: Promise.allSettled([...]), czy do: Promise.all([]), i dlatego kod się zawiesza. Tylko nie wiem, jak poznać, że: this.catch, w tym przypadku, jego obietnica, nigdy nie zostanie rozwinięta, a w: this.then, już tak. Pytanie: Jak to poznać?

Tutaj chodzi, o tą część kodu:

var wynik=this.catch(function(data){});
return Promise.all([wynik]);
1

Wydaje mi się, że mamy tutaj do czynienia z problemem X/Y - jaki jest Twój ostateczny cel / przyczyna robienia tego, co robisz teraz?

0
Patryk27 napisał(a):

Wydaje mi się, że mamy tutaj do czynienia z problemem X/Y - jaki jest Twój ostateczny cel / przyczyna robienia tego, co robisz teraz?

Tylko nie wiadomo, jak się dowiedzieć, że promise z: var promise=this.catch(function(data){}), nigdy nie zostanie rozwinięty, a z: var promise=this.then(function(data){}), już tak.

0

Ok, ale po co musisz to wiedzieć? high-level, high-level, high-level

1
gabus napisał(a):

Jak mamy kod:

promise.DodatkiSkryptThen(function(data){}).DodatkiSkryptCatch(function(data){});

to zauważ, że kod we wnętrzu, tutaj: function(data){}, w funkcji: .DodatkiSkryptThen, zostanie wykonany, i jego obietnica zostanie rozwinięta, a w: .DodatkiSkryptCatch, już nie, i dlatego: wynik=this.then, nie blokuje, a wynik=this.catch blokuje, jeśli wynik wstawimy do: Promise.allSettled([...]), czy do: Promise.all([]), i dlatego kod się zawiesza. Tylko nie wiem, jak poznać, że: this.catch, w tym przypadku, jego obietnica, nigdy nie zostanie rozwinięta, a w: this.then, już tak. Pytanie: Jak to poznać?

Tutaj chodzi, o tą część kodu:

var wynik=this.catch(function(data){});
return Promise.all([wynik]);

Jeśli promise w trakcie wykonywania zostanie odrzucony przez reject, lub zgłoszony wyjątek throw new Error('...') to pomija wszystkie wywołania pierwszego argumentu then do momentu natrafienia na catch. Po wywołaniu catch z powrotem uruchamia then.

new Promise((resolve, reject) => {
  reject('Wystąpił błąd aplikacji'); // Ustawiamy komunikat
})
.then(() => {
   // Ten fragment nie zostanie wykonany, ponieważ zostało wywołane "reject"
 })
.then(() => {
   // Ten tak samo
 })
.catch((result) => {
  console.dir(result); // Wyświetlamy komunikat o błędzie

  return 'Problem został rozwiązany';
})
.then((result) => {
  console.dir(result); // Wyświetlamy komunikat o naprawie

  return result; // Przekazujemy wynik do kolejnego "then"
})
.then((result) => {
   // ...
 });

Jeśli po drodze nie było żadnego problemu to catch nie zostanie w ogóle wywołane.

1

Właśnie, może wcale nie chodzi o to, że się coś blokuje, tylko że zostaje rzucony wyjątek, który przerywa działanie aplikacji.

To co w końcu jest w tym kodzie? Co mówią dev toolsy? (tam masz konsolę błedów czy np. profiler w zakładce performance, który ci powie, czemu ci się tam blokuje).

Być może masz faktycznie np. wieczną pętlę, ale to trzeba zlokalizować.

gabus napisał(a):

Jak mamy kilka obietnic, z pewnymi modyfikacjami w nich pewnej zmiennej, a w nim muteksu można sposodować, że jakaś zmienna jest tylko w danym momencie jest modyfikowana tylko raz.

Mutacje jednej rzeczy w różnych miejscach mogą być faktycznie problemem.

W Rust to lepiej rozwiązali, bo są tam mechanizmy na poziomie języka, żeby to wykryć i przypilnować.

W JS natomiast zalecane jest niemutowanie zmiennych po prostu, programowanie funkcyjne, a jeśli nie możesz, to przynajmniej dyscyplina w tym mutowaniu. Zepchnięcie mutacji na peryferia aplikacji.

0
LukeJL napisał(a):

Właśnie, może wcale nie chodzi o to, że się coś blokuje, tylko że zostaje rzucony wyjątek, który przerywa działanie aplikacji.

To co w końcu jest w tym kodzie? Co mówią dev toolsy? (tam masz konsolę błedów czy np. profiler w zakładce performance, który ci powie, czemu ci się tam blokuje).

Być może masz faktycznie np. wieczną pętlę, ale to trzeba zlokalizować.

gabus napisał(a):

Jak mamy kilka obietnic, z pewnymi modyfikacjami w nich pewnej zmiennej, a w nim muteksu można sposodować, że jakaś zmienna jest tylko w danym momencie jest modyfikowana tylko raz.

Mutacje jednej rzeczy w różnych miejscach mogą być faktycznie problemem.

W Rust to lepiej rozwiązali, bo są tam mechanizmy na poziomie języka, żeby to wykryć i przypilnować.

W JS natomiast zalecane jest niemutowanie zmiennych po prostu, programowanie funkcyjne, a jeśli nie możesz, to przynajmniej dyscyplina w tym mutowaniu. Zepchnięcie mutacji na peryferia aplikacji.

Jak usunąłem główny muteks w jQuery.fn.DodatkiSkryptReady, to program w JS poprawnie działa. Jak zauważyłem w mojej funkcji: Promise.prototype.DodatkiSkryptThen i Promise.prototype.DodatkiSkryptCatch, bez tego usunięcia, funkcja, .then zgłasza "<state>:pedding"., tak jak by coś blokowało, nawet jak zmieniłem na inny muteks osobny niepowtarzalny w jQuery.fn.DodatkiSkryptReady wspólny dla Promise.prototype.DodatkiSkryptThen i Promise.prototype.DodatkiSkryptCatch, ten problem nadal występuje.

0

Naprawiłem ten problem, powinno być:

var muteks_ready=new Common.Muteks();
jQuery.fn.DodatkiSkryptReady=function(__FUNKCJA,generowane_watki_2,muteks_ready_2,na_poczatku_muteksu){
	var __generowane_watki=(generowane_watki_2)?generowane_watki_2:generowane_watki;
	var __muteks_ready=(muteks_ready_2)?muteks_ready_2:muteks_ready;
	/**/
	var promise1=__generowane_watki.wygeneruj(1);//funkcja dodająca jeden do licznika liczby Promise
	var promise2=__muteks_ready.zablokuj(na_poczatku_muteksu);//muteks
	return Promise.allSettled([promise1,promise2]).then(function(data){
		var promise=__FUNKCJA(null,null,generowane_watki_2);//funkcja na którą będziemy czekać
		return Promise.allSettled([promise]).then(function(data){
			__generowane_watki.zwolnij();//funkcja odejmująca o jeden od licznika liczby Promise
			__muteks_ready.odblokuj();//odblokowanie muteksu
				return promise;
		});
	});
}
Promise.prototype.DodatkiSkryptThen=function(...args){
    return jQuery.fn.DodatkiSkryptReady(function(){return Promise.resolve();}).then(function(){
    	var promise=generowane_watki.wygeneruj(1);
    	var wynik=this.then(...args);
    	return Promise.allSettled([promise,wynik]).then(function(){//1
        	generowane_watki.zwolnij();
    		return wynik;
    	});
     });
}
Promise.prototype.DodatkiSkryptCatch=function(...args){
    return jQuery.fn.DodatkiSkryptReady(function(){return Promise.resolve();}).then(function(){
    	var promise=generowane_watki.wygeneruj(1);
    	var wynik=this.catch(...args);
    	return Promise.allSettled([promise,wynik]).then(function(){//2
        	generowane_watki.zwolnij();
    		return wynik;
    	});
    });
}
/*A wywołanie*/
var promise=new Promise(function(resolve,reject){
  resolve();
});
promise.DodatkiSkryptThen(function(data){...}).DodatkiSkryptCatch(function(data){...});

I teraz mamy niestandardowe rozszerzenia Promise w oparciu o muteksy.

0

A jakby wyglądał ten kod, jakbyś usunął całe jQuery?
Bo teraz za bardzo nie widać, w czym jest rzeczywisty problem.

Promise.prototype.DodatkiSkryptThen=function(...args){

Modyfikowanie prototypów obiektów wbudowanych to zła praktyka. Potem twój kod może źle współpracować z kodem, który już jest https://medium.com/swlh/javascript-antipatterns-prototypes-switch-and-more-e8bce5122383

Jeśli naprawdę chcesz rozszerzyć obiekt promise, to możesz zrobić własną klasę dziedziczącą z Promise

class MyPromise extends Promise {
   DodatkiSkryptThen() {
      // twoja funkcja
   }
}

i używać MyPromise. Powinno zadziałać (ale szczerze mówiąc nigdy nie miałem potrzeby czegoś takiego robić. Ja bym to raczej rozwiązał np. poprzez jakieś luźne funkcje utilsowe opakowujące promisy, jeżeli potrzebowałbym dodać jakieś funkcjonalności. Chociaż kto wie. Może dziedziczenie z Promise też by miało sens).

A poza tym mam wrażenie, że to co robisz, to jakaś wesoła twórczość, która symuluje jakiś inny niż zwykle model programowania w JS. Jeśli tak, to polecam naukę generatorów i asynchronicznych generatorów, będziesz miał więcej elastyczności i dużo zabawy. Tam faktycznie możesz sobie symulować "wątki" (tj. tworzyć korutyny) i bawić w ich synchronizację, jeśli cię to jara.

0
LukeJL napisał(a):

Jeśli naprawdę chcesz rozszerzyć obiekt promise, to możesz zrobić własną klasę dziedziczącą z Promise

class MyPromise extends Promise {
   DodatkiSkryptThen() {
      // twoja funkcja
   }
}

i używać MyPromise. Powinno zadziałać (ale szczerze mówiąc nigdy nie miałem potrzeby czegoś takiego robić. Ja bym to raczej rozwiązał np. poprzez jakieś luźne funkcje utilsowe opakowujące promisy, jeżeli potrzebowałbym dodać jakieś funkcjonalności. Chociaż kto wie. Może dziedziczenie z Promise też by miało sens).

Może klasa: MyPromise, ma takie same funkcje, co Promise, plus własne, ale trzeba używać: MyPromise, zamiast: Promise, gorzej jak: Promise, jest używany w funkcji napisanego przez innego autora, lub funkcja zwraca : Object, w którym są zawarte funkcje obietnicy: jQuery, i wtedy jest zwracana przez tą funkcje obietnica: Promise, JS, lub obietnice zdefiniowane w bibliotece: jQuery.

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