Asynchroniczny i jednowątkowy JavaScript?
JavaScript jest językiem jednowątkowym, a jednocześnie nieblokującym, asynchronicznym i współbieżnym. Ten artykuł wyjaśni ci, jak to się dzieje.
Sprawdź trzecią część naszej serii artykułów Power of functional programming w JavaScript. Tym razem nasz ekspert JavaScript wyjaśnia więcej na temat Functor i Monad Maybe.
Często zachowanie niemodyfikowalności jest trudne do utrzymania. Z pomocą przychodzi wzorzec opakowywania danych w kontener. Zabezpiecza on wartości tak, że operowanie na nich jest bezpieczne z wykluczeniem efektów ubocznych.
Jeśli jesteś tu nowy, koniecznie sprawdź moje ostatnie 2 części dotyczące programowania funkcjonalnego na blogu The Codest:
Nie ma złożonej logiki. Jego głównym zadaniem jest opakowywanie kontekstu i wykonywanie na nim funkcji, które otrzymuje z zewnątrz. Za każdym razem, gdy zmienia się wartość, nowa instancja kontenera jest przepakowywana i zwracana. Podczas wywoływania funkcji mapa która wykonuje określoną akcję, zwraca nową instancję kontenera z wartością zwróconą przez przekazaną funkcję, zachowując zasadę niemodyfikowalności.
const Functor = value => ({
map: fn => Functor(fn(value)),
chain: fn => fn(value),
of: () => value
});
mapa - przydatna, gdy chcesz zmienić stan wartości w kontenerze, ale nie chcesz jej jeszcze zwracać.
łańcuch - używany, jeśli chcesz przekazać wartość do funkcji bez modyfikowania stanu kontenera. Zwykle na końcu mapa połączenia.
z - zwraca bieżącą wartość
const randomInt = (max) => Math.floor(Math.random() * (max + 1))
const randomNumber = randomInt(200) // zwraca liczbę pomiędzy 0 a 200
decrease(randomNumber) // zwraca (liczbę pomiędzy 0 a 200) - 1
const randomIntWrapper = (max) =>
Functor(max)
.map(increase) // max + 1
.map(multiplyBy(Math.random())) // Math.random() * (max + 1)
.map(Math.floor) // Math.floor(Math.random() * (max + 1))
const randomNumber = randomIntWrapper(200)
randomNumber.of() // zwraca liczbę pomiędzy 0 a 200
randomNumber.chain(decrease) // zwraca (liczbę między 0 a 200) - 1
Czasami, oprócz funkcji wywołujących nowy stan wartości, potrzebna jest dodatkowa logika ukryta w kontenerze. Tutaj przydaje się monada, która jest rozszerzeniem funkcji funktor. Może na przykład zdecydować, co powinno się stać, gdy wartość ma określoną wartość lub jaką ścieżkę mają obrać kolejne działania.
Monada być może rozwiązuje problem wartości, które nie zwracają prawdy. Kiedy tak się dzieje, kolejne mapa są ignorowane, ale umożliwia zwrócenie alternatywy poprzez wywołanie funkcji getOr method. Pozwala to uniknąć stosowania operatorów if / else, które są popularne w metodach imperatywny programowanie. Monada ta składa się z trzech kontenerów:
Nic - uruchamia się, gdy wartość, która nie jest prawdziwa, wpada do kontenera lub filtr zwraca wartość false. Służy do symulacji wykonania funkcji. Oznacza to, że ten kontener odbiera funkcję, ale jej nie wykonuje.
Po prostu - jest to główny kontener, który wykonuje wszystkie funkcje, ale jeśli wartość zmieni się na wartość false lub filtr zwróci wartość false, przekaże ją do metody Nic pojemnik.
Może - Biorę wartość początkową i decyduję, który kontener wywołać na początku.
const Just = value => ({
map: fn => Maybe(fn(value)),
chain: fn => fn(value),
of: () => value,
getOr: () => value,
filter: fn => fn(value) ? Just(value) : Nothing(),
type: 'just'
});
const Nothing = () => ({
map: fn => Nothing(),
chain: fn => fn(),
of: () => Nothing(),
getOr: substitute => substitute,
filter: () => Nothing(),
type: 'nothing'
});
const Maybe = value =>
value == null || value == undefined || value.type == 'nothing'
? Nothing()
: Just(value)
Rozbudujmy teraz poprzedni przykład o warunek. Jeśli wartość max jest większa od zera, funkcja zostanie wykonana. W przeciwnym razie funkcja zwróci 0.
const randomInt = (max) => {
if(max > 0) {
return Math.floor(Math.random() * (max + 1))
} else {
return 0
}
}
const bookMiddlePage = 200
const randomPage = randomInt(10) || bookMiddlePage // zwraca losową wartość
const randomPage = randomInt(-10) || bookMiddlePage // zwraca 200
const randomIntWrapper = (max) =>
Maybe(max)
.filter(max => max > 0) // wartość false ignoruje dalsze wywołania
.map(increase)
.map(multiplyBy(Math.random()))
.map(Math.floor)
const bookMiddlePage = 200
// Tylko kontener
const randomPage = randomIntWrapper(10).getOr(bookMiddlePage) // zwraca losową wartość
// Kontener bez niczego
const randomPage = randomIntWrapper(-10).getOr(bookMiddlePage) // zwraca 200