Skip to content
Mithril.js 2
Main Navigation PrzewodnikAPI

Polski

English
简体中文
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Türkçe
čeština
magyar

Polski

English
简体中文
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Türkçe
čeština
magyar

Wygląd

Sidebar Navigation

API

Podstawowe API

m(selector, attributes, children)

render(element, vnodes)

mount(root, component)

route(root, defaultRoute, routes)

request(options)

parseQueryString(string)

buildQueryString(object)

buildPathname(object)

parsePathname(string)

trust(html)

fragment(attrs, children)

redraw()

censor(obiekt, extra)

Opcjonalne API

stream()

Przewodnik

Na tej stronie

stream() ​

Opis ​

Strumień to reaktywna struktura danych, działająca podobnie do komórek w arkuszach kalkulacyjnych.

Na przykład, w arkuszu kalkulacyjnym, jeśli A1 = B1 + C1, to zmiana wartości B1 lub C1 automatycznie zmieni wartość A1.

Podobnie, możesz zdefiniować strumień, który zależy od innych strumieni, tak aby zmiana wartości jednego automatycznie aktualizowała drugi. Jest to przydatne, gdy masz kosztowne obliczenia i chcesz je uruchamiać tylko wtedy, gdy jest to konieczne, zamiast przy każdym odświeżeniu (redraw).

Strumienie nie są częścią podstawowej dystrybucji Mithril.js. Aby dołączyć moduł Streams, użyj:

javascript
var Stream = require('mithril/stream');

Możesz również pobrać moduł bezpośrednio, jeśli twoje środowisko nie obsługuje narzędzi do bundlingu:

html
<script src="https://unpkg.com/mithril/stream/stream.js"></script>

Po załadowaniu bezpośrednio za pomocą tagu <script> (zamiast require), biblioteka strumieni będzie dostępna jako window.m.stream. Jeśli window.m jest już zdefiniowane (np. dlatego, że używasz również głównego skryptu Mithril.js), dołączy się do istniejącego obiektu. W przeciwnym razie tworzy nowy window.m. Jeśli chcesz używać strumieni w połączeniu z Mithril.js jako surowe tagi skryptów, powinieneś dołączyć Mithril.js do swojej strony przed mithril/stream, ponieważ mithril w przeciwnym razie nadpisze obiekt window.m zdefiniowany przez mithril/stream. Nie stanowi to problemu, gdy biblioteki są używane jako moduły CommonJS (za pomocą require(...)).

Sygnatura ​

Tworzy nowy strumień.

stream = Stream(value)

ArgumentTypWymaganyOpis
valueanyNieJeśli ten argument jest obecny, wartość strumienia jest ustawiana na niego.
zwracaStreamZwraca strumień.

Jak interpretować sygnatury

Statyczne elementy członkowskie ​

Stream.combine ​

Tworzy strumień obliczeniowy, który aktualizuje się reaktywnie, jeśli którykolwiek z jego strumieni wejściowych zostanie zaktualizowany. Zobacz łączenie strumieni.

stream = Stream.combine(combiner, streams)

ArgumentTypWymaganyOpis
combiner(Stream..., Array) -> anyTakSzczegóły w opisie argumentu combiner.
streamsArray<Stream>TakLista strumieni do połączenia.
zwracaStreamZwraca strumień.

Jak interpretować sygnatury

combiner ​

Określa, w jaki sposób generowana jest wartość strumienia obliczeniowego. Zobacz łączenie strumieni.

any = combiner(streams..., changed)

ArgumentTypWymaganyOpis
streams...splat of StreamsNieSplat strumieni, które odpowiadają strumieniom przekazanym jako drugi argument do stream.combine.
changedArray<Stream>TakLista strumieni, które spowodowały aktualizację.
zwracaanyZwraca obliczoną wartość.

Jak interpretować sygnatury

Stream.merge ​

Tworzy strumień, którego wartością jest tablica wartości ze strumieni wejściowych.

stream = Stream.merge(streams)

ArgumentTypWymaganyOpis
streamsArray<Stream>TakLista strumieni.
zwracaStreamZwraca strumień zawierający tablicę wartości ze strumieni wejściowych.

Jak interpretować sygnatury

Stream.scan ​

Tworzy nowy strumień z wynikami wywołania funkcji na każdej wartości w strumieniu, z akumulatorem i wartością przychodzącą.

Zauważ, że możesz zapobiec aktualizacji zależnych strumieni, zwracając specjalną wartość Stream.SKIP wewnątrz funkcji akumulatora.

stream = Stream.scan(fn, accumulator, stream)

ArgumentTypWymaganyOpis
fn(accumulator, value) -> result | SKIPTakFunkcja, która przyjmuje akumulator i wartość, a następnie zwraca nową wartość akumulatora (tego samego typu).
accumulatoranyTakWartość początkowa dla akumulatora.
streamStreamTakStrumień zawierający wartości.
zwracaStreamZwraca nowy strumień zawierający wynik.

Jak interpretować sygnatury

Stream.scanMerge ​

Pobiera tablicę par strumieni i funkcji skanowania i łączy wszystkie te strumienie za pomocą podanych funkcji w jeden strumień.

stream = Stream.scanMerge(pairs, accumulator)

ArgumentTypWymaganyOpis
pairsArray<[Stream, (accumulator, value) -> value]>TakTablica par: strumień i funkcja skanowania.
accumulatoranyTakWartość początkowa dla akumulatora.
zwracaStreamZwraca nowy strumień zawierający wynik.

Jak interpretować sygnatury

Stream.lift ​

Tworzy strumień obliczeniowy, który aktualizuje się reaktywnie, jeśli którykolwiek z jego strumieni wejściowych zostanie zaktualizowany. Zobacz łączenie strumieni. W przeciwieństwie do combine, strumienie wejściowe są przekazywane jako zmienna liczba argumentów (zamiast tablicy), a funkcja zwrotna (callback) otrzymuje wartości strumieni zamiast strumieni. Nie ma parametru changed. Jest to ogólnie bardziej przyjazna dla użytkownika funkcja niż combine.

stream = Stream.lift(lifter, stream1, stream2, ...)

ArgumentTypWymaganyOpis
lifter(any...) -> anyTakZobacz argument lifter.
streams...list of StreamsTakStrumienie, które zostaną przetworzone przez funkcję lifter.
zwracaStreamZwraca strumień.

Jak interpretować sygnatury

lifter ​

Określa, w jaki sposób generowana jest wartość strumienia obliczeniowego. Zobacz łączenie strumieni.

any = lifter(streams...)

ArgumentTypWymaganyOpis
streams...splat of StreamsNieSplat strumieni, które odpowiadają wartościom strumieni przekazanych do stream.lift.
zwracaanyZwraca obliczoną wartość.

Jak interpretować sygnatury

Stream.SKIP ​

Specjalna wartość (SKIP), która może być zwracana w callbackach strumienia, aby pominąć wykonanie zależnych strumieni.

Stream["fantasy-land/of"] ​

Ta metoda jest funkcjonalnie identyczna z stream. Istnieje, aby być zgodną ze specyfikacją Applicative Fantasy Land. Więcej informacji można znaleźć w sekcji Czym jest Fantasy Land.

stream = Stream["fantasy-land/of"](value)

ArgumentTypWymaganyOpis
valueanyNieJeśli ten argument jest obecny, wartość strumienia jest ustawiana na niego.
zwracaStreamZwraca strumień.

Elementy członkowskie instancji ​

stream.map ​

Tworzy zależny strumień, którego wartość jest ustawiana na wynik callbacku. Ta metoda jest aliasem stream["fantasy-land/map"].

dependentStream = stream().map(callback)

ArgumentTypWymaganyOpis
callbackany -> anyTakFunkcja, której wynik staje się wartością strumienia.
zwracaStreamZwraca strumień.

Jak interpretować sygnatury

stream.end ​

Strumień, który wyrejestrowuje zależne strumienie, gdy jest ustawiony na true. Zobacz stan zakończony.

endStream = stream().end

stream["fantasy-land/of"] ​

Ta metoda jest funkcjonalnie identyczna z stream. Istnieje, aby być zgodną ze specyfikacją Applicative Fantasy Land. Więcej informacji można znaleźć w sekcji Czym jest Fantasy Land.

stream = stream()["fantasy-land/of"](value)

ArgumentTypWymaganyOpis
valueanyNieJeśli ten argument jest obecny, wartość strumienia jest ustawiana na niego.
zwracaStreamZwraca strumień.

stream["fantasy-land/map"] ​

Tworzy zależny strumień, którego wartość jest ustawiana na wynik callbacku. Zobacz łańcuchowe łączenie strumieni.

Ta metoda istnieje, aby być zgodną ze specyfikacją Applicative Fantasy Land. Więcej informacji można znaleźć w sekcji Czym jest Fantasy Land.

dependentStream = stream()["fantasy-land/map"](callback)

ArgumentTypWymaganyOpis
callbackany -> anyTakFunkcja, której wynik staje się wartością strumienia.
zwracaStreamZwraca strumień.

Jak interpretować sygnatury

stream["fantasy-land/ap"] ​

Nazwa tej metody oznacza apply (zastosuj). Jeśli strumień a ma funkcję jako swoją wartość, inny strumień b może użyć go jako argumentu do b.ap(a). Wywołanie ap wywoła funkcję z wartością strumienia b jako argumentem i zwróci inny strumień, którego wartością jest wynik wywołania funkcji. Ta metoda istnieje, aby być zgodną ze specyfikacją Applicative Fantasy Land. Więcej informacji można znaleźć w sekcji Czym jest Fantasy Land.

stream = stream()["fantasy-land/ap"](apply)

ArgumentTypWymaganyOpis
applyStreamTakStrumień, którego wartością jest funkcja.
zwracaStreamZwraca strumień.

Podstawowe użycie ​

Strumienie nie są częścią podstawowej dystrybucji Mithril.js. Aby dołączyć je do projektu, zaimportuj (require) jego moduł:

javascript
var stream = require('mithril/stream');

Strumienie jako zmienne ​

stream() zwraca strumień. Na najbardziej podstawowym poziomie, strumień działa podobnie do zmiennej lub właściwości getter-setter: może przechowywać stan, który można modyfikować.

javascript
var username = stream('John');
console.log(username()); // loguje "John"

username('John Doe');
console.log(username()); // loguje "John Doe"

Główna różnica polega na tym, że strumień jest funkcją, a zatem może być używany w funkcjach wyższego rzędu.

javascript
var users = stream();

// pobierz użytkowników z serwera za pomocą API fetch
fetch('/api/users')
  .then(function (response) {
    return response.json();
  })
  .then(users);

W powyższym przykładzie, strumień users jest wypełniany danymi odpowiedzi, gdy żądanie zostanie rozwiązane (resolve).

Powiązania dwukierunkowe ​

Dwukierunkowe powiązanie ze strumieniem może być również realizowane z użyciem callbacków zdarzeń.

javascript
// strumień
var user = stream('');

// powiązanie dwukierunkowe ze strumieniem
m('input', {
  oninput: function (e) {
    user(e.target.value);
  },
  value: user(),
});

W powyższym przykładzie, gdy użytkownik wpisuje tekst w polu input, strumień user jest aktualizowany do wartości pola input.

Właściwości obliczeniowe ​

Strumienie są przydatne do implementowania właściwości obliczeniowych:

javascript
var title = stream('');
var slug = title.map(function (value) {
  return value.toLowerCase().replace(/\W/g, '-');
});

title('Hello world');
console.log(slug()); // loguje "hello-world"

W powyższym przykładzie, wartość slug jest obliczana, gdy title jest aktualizowany, a nie gdy slug jest odczytywany.

Oczywiście możliwe jest również obliczanie właściwości na podstawie wielu strumieni:

javascript
var firstName = stream('John');
var lastName = stream('Doe');
var fullName = stream.merge([firstName, lastName]).map(function (values) {
  return values.join(' ');
});

console.log(fullName()); // loguje "John Doe"

firstName('Mary');

console.log(fullName()); // loguje "Mary Doe"

Mithril.js aktualizuje właściwości obliczeniowe atomowo. Oznacza to, że strumienie zależne od wielu innych strumieni zostaną wywołane tylko raz na aktualizację wartości, niezależnie od złożoności grafu zależności.

Łączenie strumieni ​

Strumienie można łączyć za pomocą metody map. Strumień utworzony za pomocą map nazywany jest również strumieniem zależnym.

javascript
// strumień nadrzędny
var value = stream(1);

// strumień zależny
var doubled = value.map(function (value) {
  return value * 2;
});

console.log(doubled()); // loguje 2

Strumienie zależne są reaktywne: ich wartości są aktualizowane za każdym razem, gdy wartość ich strumienia nadrzędnego jest aktualizowana. Dzieje się tak niezależnie od tego, czy strumień zależny został utworzony przed, czy po ustawieniu wartości strumienia nadrzędnego.

Możesz zapobiec aktualizacji zależnych strumieni, zwracając specjalną wartość Stream.SKIP.

javascript
var skipped = stream(1).map(function (value) {
  return stream.SKIP;
});

skipped.map(function () {
  // nigdy się nie uruchomi
});

Kombinowanie strumieni ​

Strumienie mogą zależeć od więcej niż jednego strumienia nadrzędnego. Tego rodzaju strumienie można tworzyć za pomocą stream.merge()

javascript
var a = stream('hello');
var b = stream('world');

var greeting = stream.merge([a, b]).map(function (values) {
  return values.join(' ');
});

console.log(greeting()); // loguje "hello world"

Lub możesz użyć funkcji pomocniczej stream.lift()

javascript
var a = stream('hello');
var b = stream('world');

var greeting = stream.lift(
  function (_a, _b) {
    return _a + ' ' + _b;
  },
  a,
  b
);

console.log(greeting()); // loguje "hello world"

Metoda stream.combine() to funkcja niższego poziomu, która udostępnia strumienie bezpośrednio w obliczeniach reaktywnych, co pozwala na bardziej zaawansowane zastosowania.

javascript
var a = stream(5);
var b = stream(7);

var added = stream.combine(
  function (a, b) {
    return a() + b();
  },
  [a, b]
);

console.log(added()); // loguje 12

Strumień może zależeć od dowolnej liczby strumieni i gwarantuje się, że będzie aktualizowany atomowo. Na przykład, jeśli strumień A ma dwa zależne strumienie B i C, a czwarty strumień D jest zależny zarówno od B, jak i C, strumień D zaktualizuje się tylko raz, jeśli wartość A się zmieni. Gwarantuje to, że callback dla strumienia D nigdy nie zostanie wywołany z niestabilnymi wartościami, takimi jak wtedy, gdy B ma nową wartość, ale C ma starą wartość. Atomowość przynosi również korzyści wydajnościowe w postaci braku niepotrzebnego ponownego obliczania zależnych strumieni.

Możesz zapobiec aktualizacji zależnych strumieni, zwracając specjalną wartość Stream.SKIP.

javascript
var skipped = stream.combine(
  function (stream) {
    return stream.SKIP;
  },
  [stream(1)]
);

skipped.map(function () {
  // nigdy się nie uruchomi
});

Stany strumienia ​

Strumień może znajdować się w jednym z trzech stanów: oczekującym (pending), aktywnym (active) lub zakończonym (ended).

Stan oczekujący ​

Strumienie w stanie oczekującym można utworzyć, wywołując stream() bez parametrów.

javascript
var pending = stream();

Jeśli strumień jest zależny od więcej niż jednego strumienia, a którykolwiek z jego strumieni nadrzędnych jest w stanie oczekującym, strumień zależny jest również w stanie oczekującym i nie aktualizuje swojej wartości.

javascript
var a = stream(5);
var b = stream(); // strumień w stanie oczekującym

var added = stream.combine(
  function (a, b) {
    return a() + b();
  },
  [a, b]
);

console.log(added()); // loguje undefined

W powyższym przykładzie, added jest strumieniem w stanie oczekującym, ponieważ jego strumień nadrzędny b jest również w stanie oczekującym.

Dotyczy to również strumieni zależnych utworzonych za pomocą stream.map:

javascript
var value = stream();
var doubled = value.map(function (value) {
  return value * 2;
});

console.log(doubled()); // loguje undefined, ponieważ `doubled` jest w stanie oczekującym

Stan aktywny ​

Gdy strumień otrzyma wartość, staje się aktywny (chyba że strumień jest zakończony).

javascript
var stream1 = stream('hello'); // stream1 jest aktywny

var stream2 = stream(); // stream2 zaczyna w stanie oczekującym
stream2('world'); // a następnie staje się aktywny

Strumień zależny z wieloma strumieniami nadrzędnymi staje się aktywny, jeśli wszystkie jego strumienie nadrzędne są aktywne.

javascript
var a = stream('hello');
var b = stream();

var greeting = stream.merge([a, b]).map(function (values) {
  return values.join(' ');
});

W powyższym przykładzie, strumień a jest aktywny, ale b jest w stanie oczekującym. Ustawienie b("world") spowodowałoby, że b stałby się aktywny, a zatem greeting również stałby się aktywny i zostałby zaktualizowany do wartości "hello world".

Stan zakończony ​

Strumień może przestać wpływać na swoje zależne strumienie, wywołując stream.end(true). To skutecznie usuwa połączenie między strumieniem a jego zależnymi strumieniami.

javascript
var value = stream();
var doubled = value.map(function (value) {
  return value * 2;
});

value.end(true); // ustaw stan zakończony

value(5);

console.log(doubled());
// loguje undefined, ponieważ `doubled` nie zależy już od `value`

Strumienie w stanie zakończonym nadal mają semantykę kontenera stanu (state container), tj. nadal można ich używać jako getter-setterów, nawet po ich zakończeniu.

javascript
var value = stream(1);
value.end(true); // ustaw stan zakończony

console.log(value(1)); // loguje 1

value(2);
console.log(value()); // loguje 2

Zakończenie strumienia może być przydatne w przypadkach, gdy strumień ma ograniczoną żywotność (na przykład, reagowanie na zdarzenia mousemove tylko wtedy, gdy element DOM jest przeciągany, ale nie po jego upuszczeniu).

Serializacja strumieni ​

Strumienie implementują metodę .toJSON(). Gdy strumień jest przekazywany jako argument do funkcji JSON.stringify(), wartość strumienia jest serializowana.

javascript
var value = stream(123);
var serialized = JSON.stringify(value);
console.log(serialized); // loguje 123

Strumienie nie wywołują renderowania ​

W przeciwieństwie do bibliotek takich jak Knockout, strumienie Mithril.js nie wywołują ponownego renderowania szablonów. Odświeżanie (redrawing) odbywa się w odpowiedzi na obsługę zdarzeń zdefiniowaną w widokach komponentów Mithril.js, zmiany trasy lub po rozwiązaniu wywołań m.request.

Jeśli odświeżanie jest pożądane w odpowiedzi na inne zdarzenia asynchroniczne (np. setTimeout/setInterval, subskrypcja websocket, obsługa zdarzeń biblioteki zewnętrznej), należy ręcznie wywołać m.redraw().

Czym jest Fantasy Land ​

Fantasy Land określa interoperacyjność wspólnych struktur algebraicznych. Prościej mówiąc, biblioteki zgodne ze specyfikacją Fantasy Land pozwalają na pisanie uniwersalnego kodu funkcyjnego, niezależnie od wewnętrznej implementacji poszczególnych bibliotek.

Na przykład, powiedzmy, że chcemy utworzyć ogólną funkcję o nazwie plusOne. Naiwna implementacja wyglądałaby tak:

javascript
function plusOne(a) {
  return a + 1;
}

Problem z tą implementacją polega na tym, że można jej używać tylko z liczbą. Jednak możliwe jest, że logika generująca wartość dla a może również generować stan błędu (opakowany w Maybe lub Either z biblioteki takiej jak Sanctuary lub Ramda-Fantasy), lub może to być strumień Mithril.js, strumień Flyd itp. Idealnie, nie chcielibyśmy pisać podobnej wersji tej samej funkcji dla każdego możliwego typu, jaki a może mieć i nie chcielibyśmy pisać kodu opakowującego/rozpakowującego/obsługi błędów wielokrotnie.

W tym miejscu Fantasy Land może pomóc. Przepiszmy tę funkcję w kategoriach algebry Fantasy Land:

javascript
var fl = require('fantasy-land');

function plusOne(a) {
  return a[fl.map](function (value) {
    return value + 1;
  });
}

Teraz ta metoda działa z dowolnym zgodnym z Fantasy Land Funktorem, takim jak R.Maybe, S.Either, stream itp.

Ten przykład może wydawać się zawiły, ale jest to kompromis w złożoności: naiwna implementacja plusOne ma sens, jeśli masz prosty system i tylko zwiększasz liczby, ale implementacja Fantasy Land staje się potężniejsza, jeśli masz duży system z wieloma abstrakcjami opakowującymi i algorytmami wielokrotnego użytku.

Decydując, czy powinieneś przyjąć Fantasy Land, powinieneś wziąć pod uwagę znajomość programowania funkcyjnego przez twój zespół i być realistą co do poziomu dyscypliny, jaki twój zespół może zobowiązać się do utrzymania jakości kodu (w porównaniu z presją pisania nowych funkcji i dotrzymywania terminów). Programowanie w stylu funkcyjnym w dużym stopniu zależy od kompilowania, kuratorowania i opanowywania dużego zestawu małych, precyzyjnie zdefiniowanych funkcji, a zatem nie jest odpowiednie dla zespołów, które nie mają solidnych praktyk dokumentacyjnych i/lub brakuje im doświadczenia w językach zorientowanych funkcyjnie.

Pager
Poprzednia stronacensor(obiekt, extra)
Następna stronaPrzewodnik

Opublikowano na licencji MIT.

Copyright (c) 2024 Mithril Contributors

https://mithril.js.org/stream.html

Opublikowano na licencji MIT.

Copyright (c) 2024 Mithril Contributors