Skip to content
Mithril.js 2
Main Navigation NávodAPI

čeština

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

čeština

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

Vzhled

Sidebar Navigation

API

Základní 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(object, extra)

Volitelné API

stream()

Návod

Na této stránce

stream() ​

Popis ​

Stream je reaktivní datová struktura, podobná buňkám v tabulkových aplikacích.

Například, v tabulce, pokud A1 = B1 + C1, pak změna hodnoty B1 nebo C1 automaticky změní hodnotu A1.

Podobně můžete vytvořit stream, který závisí na jiných streamech, takže změna hodnoty jednoho automaticky aktualizuje druhý. To je užitečné, když máte výpočetně náročné operace a chcete je spouštět pouze v případě potřeby, například ne při každém překreslení.

Streamy nejsou součástí základní distribuce Mithril.js. Chcete-li zahrnout modul Stream, použijte:

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

Modul si můžete také stáhnout přímo, pokud vaše prostředí nepodporuje nástroj pro vytváření balíčků:

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

Při načítání přímo pomocí tagu <script> (spíše než pomocí require), bude knihovna streamů zpřístupněna jako window.m.stream. Pokud již existuje window.m (např. protože také používáte hlavní skript Mithril.js), připojí se k existujícímu objektu. Jinak vytvoří nový window.m. Pokud chcete používat streamy ve spojení s Mithril.js jako surové skriptové tagy, měli byste zahrnout Mithril.js do své stránky před mithril/stream, protože mithril jinak přepíše objekt window.m definovaný mithril/stream. To se netýká případů, kdy jsou knihovny používány jako moduly CommonJS (pomocí require(...)).

Signatura ​

Vytvoří nový stream.

stream = Stream(value)

ArgumentTypPovinnýPopis
valueanyNePokud je tento argument přítomen, hodnota streamu je na něj nastavena.
returnsStreamVrací instanci streamu.

Jak číst signatury

Statické členy ​

Stream.combine ​

Vytvoří stream, který se počítá a reaktivně aktualizuje, pokud se aktualizuje některý z jeho upstreamů. Viz kombinování streamů.

stream = Stream.combine(combiner, streams)

ArgumentTypPovinnýPopis
combiner(Stream..., Array) -> anyAnoViz argument combiner.
streamsArray<Stream>AnoSeznam streamů, které budou kombinovány.
returnsStreamVrací instanci streamu.

Jak číst signatury

combiner ​

Určuje, jak je generována hodnota počítaného streamu. Viz kombinování streamů.

any = combiner(streams..., changed)

ArgumentTypPovinnýPopis
streams...splat of StreamsNeSplat nula nebo více streamů, které odpovídají streamům předaným jako druhý argument do stream.combine.
changedArray<Stream>AnoSeznam streamů, které byly ovlivněny aktualizací.
returnsanyVrací vypočítanou hodnotu.

Jak číst signatury

Stream.merge ​

Vytvoří stream, jehož hodnota je pole hodnot z pole streamů.

stream = Stream.merge(streams)

ArgumentTypPovinnýPopis
streamsArray<Stream>AnoSeznam streamů.
returnsStreamVrací stream, jehož hodnota je pole hodnot vstupních streamů.

Jak číst signatury

Stream.scan ​

Vytvoří nový stream s výsledky volání funkce na každé hodnotě ve streamu s akumulátorem a příchozí hodnotou.

Všimněte si, že můžete zabránit aktualizaci závislých streamů tím, že vrátíte speciální hodnotu stream.SKIP uvnitř akumulační funkce.

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

ArgumentTypPovinnýPopis
fn(accumulator, value) -> result | SKIPAnoFunkce, která bere akumulátor a hodnotu jako parametry a vrací novou hodnotu akumulátoru stejného typu.
accumulatoranyAnoPočáteční hodnota pro akumulátor.
streamStreamAnoStream obsahující hodnoty.
returnsStreamVrací nový stream, který obsahuje výsledek.

Jak číst signatury

Stream.scanMerge ​

Vezme pole párů streamů a scanovacích funkcí a sloučí všechny tyto streamy pomocí daných funkcí do jednoho streamu.

stream = Stream.scanMerge(pairs, accumulator)

ArgumentTypPovinnýPopis
pairsArray<[Stream, (accumulator, value) -> value]>AnoPole párů streamu a scanovacích funkcí.
accumulatoranyAnoPočáteční hodnota pro akumulátor.
returnsStreamVrací nový stream, který obsahuje výsledek.

Jak číst signatury

Stream.lift ​

Vytvoří stream, který se počítá a reaktivně aktualizuje, pokud se aktualizuje některý z jeho upstreamů. Viz kombinování streamů. Na rozdíl od combine jsou vstupní streamy proměnný počet argumentů (místo pole) a callback obdrží hodnoty streamu místo streamů. Neexistuje parametr changed. Toto je obecně uživatelsky přívětivější funkce pro aplikace než combine.

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

ArgumentTypPovinnýPopis
lifter(any...) -> anyAnoViz argument lifter.
streams...list of StreamsAnoStreamy, které mají být "lifted".
returnsStreamVrací instanci streamu.

Jak číst signatury

lifter ​

Určuje, jak je generována hodnota počítaného streamu. Viz kombinování streamů.

any = lifter(streams...)

ArgumentTypPovinnýPopis
streams...splat of StreamsNeSplat nula nebo více hodnot, které odpovídají hodnotám streamů předaných do funkce stream.lift.
returnsanyVrací vypočítanou hodnotu.

Jak číst signatury

Stream.SKIP ​

Speciální hodnota, která může být vrácena do callbacků streamu, aby se přeskočilo spuštění downstreamů.

Stream["fantasy-land/of"] ​

Tato metoda je funkčně identická s stream. Existuje, aby vyhovovala specifikaci Applicative Fantasy Land. Pro více informací viz sekce Co je Fantasy Land.

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

ArgumentTypPovinnýPopis
valueanyNePokud je tento argument přítomen, hodnota streamu je na něj nastavena.
returnsStreamVrací instanci streamu.

Členy instance ​

stream.map ​

Vytvoří stream, který závisí na jiném a jehož hodnota je nastavena na výsledek callback funkce. Tato metoda je aliasem stream["fantasy-land/map"].

dependentStream = stream().map(callback)

ArgumentTypPovinnýPopis
callbackany -> anyAnoCallback, jehož návratová hodnota se stane hodnotou streamu.
returnsStreamVrací instanci streamu.

Jak číst signatury

stream.end ​

Spolu-závislý stream, který odregistruje závislé streamy, když je nastaven na true. Viz stav ended (ukončený).

endStream = stream().end

stream["fantasy-land/of"] ​

Tato metoda je funkčně identická s stream. Existuje, aby vyhovovala specifikaci Applicative Fantasy Land. Pro více informací viz sekce Co je Fantasy Land.

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

ArgumentTypPovinnýPopis
valueanyNePokud je tento argument přítomen, hodnota streamu je na něj nastavena.
returnsStreamVrací instanci streamu.

stream["fantasy-land/map"] ​

Vytvoří stream, který závisí na jiném a jehož hodnota je nastavena na výsledek callback funkce. Viz řetězení streamů.

Tato metoda slouží k tomu, aby vyhověla specifikaci Applicative Fantasy Land. Pro více informací viz sekce Co je Fantasy Land.

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

ArgumentTypPovinnýPopis
callbackany -> anyAnoCallback, jehož návratová hodnota se stane hodnotou streamu.
returnsStreamVrací instanci streamu.

Jak číst signatury

stream["fantasy-land/ap"] ​

Název této metody znamená apply (aplikovat). Pokud má stream a jako svou hodnotu funkci, jiný stream b ji může použít jako argument pro b.ap(a). Volání ap zavolá funkci s hodnotou streamu b jako argumentem a vrátí jiný stream, jehož hodnota je výsledkem volání funkce. Tato metoda existuje, aby vyhovovala specifikaci Applicative Fantasy Land. Pro více informací viz sekce Co je Fantasy Land.

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

ArgumentTypPovinnýPopis
applyStreamAnoStream, jehož hodnota je funkce.
returnsStreamVrací instanci streamu.

Základní použití ​

Streamy nejsou součástí základní distribuce Mithril.js. Chcete-li je zahrnout do projektu, vyžadujte jeho modul:

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

Streamy jako proměnné ​

stream() vrací stream. Na své nejzákladnější úrovni funguje stream podobně jako proměnná nebo vlastnost s getterem a setterem: může uchovávat stav, který lze upravit.

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

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

Hlavní rozdíl je v tom, že stream je funkce, a proto může být složen do funkcí vyššího řádu.

javascript
var users = stream();

// požádej o uživatele ze serveru pomocí Fetch API
fetch('/api/users')
  .then(function (response) {
    return response.json();
  })
  .then(users);

Ve výše uvedeném příkladu je stream users naplněn daty odpovědi, když se požadavek vyřeší.

Obousměrné vazby ​

Streamy lze také naplnit pomocí callbacků událostí a podobně.

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

// obousměrná vazba na stream
m('input', {
  oninput: function (e) {
    user(e.target.value);
  },
  value: user(),
});

Ve výše uvedeném příkladu, když uživatel píše do vstupu, stream user je aktualizován na hodnotu vstupního pole.

Počítané vlastnosti ​

Streamy jsou užitečné pro implementaci počítaných vlastností:

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

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

Ve výše uvedeném příkladu je hodnota slug vypočítána, když je title aktualizován, ne když je slug čten.

Je samozřejmě také možné počítat vlastnosti na základě více streamů:

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

console.log(fullName()); // zobrazí "John Doe"

firstName('Mary');

console.log(fullName()); // zobrazí "Mary Doe"

Počítané vlastnosti v Mithril.js jsou aktualizovány atomicky: streamy, které závisí na více streamech, nebudou nikdy volány více než jednou na aktualizaci hodnoty, bez ohledu na to, jak složitý je graf závislostí počítané vlastnosti.

Řetězení streamů ​

Streamy mohou být řetězeny pomocí metody map. Stream zřetězený pomocí map je také známý jako závislý stream.

javascript
// rodičovský stream
var value = stream(1);

// závislý stream
var doubled = value.map(function (value) {
  return value * 2;
});

console.log(doubled()); // zobrazí 2

Závislé streamy jsou reaktivní: jejich hodnoty jsou aktualizovány pokaždé, když je aktualizována hodnota jejich rodičovského streamu. To se děje bez ohledu na to, zda byl závislý stream vytvořen před nebo po nastavení hodnoty rodičovského streamu.

Můžete zabránit aktualizaci závislých streamů tím, že vrátíte speciální hodnotu stream.SKIP.

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

skipped.map(function () {
  // nikdy se nespustí
});

Kombinování streamů ​

Streamy mohou záviset na více než jednom rodičovském streamu. Tyto druhy streamů lze vytvořit 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()); // zobrazí "hello world"

Nebo můžete použít pomocnou funkci 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()); // zobrazí "hello world"

Existuje také metoda nižší úrovně nazvaná stream.combine(), která zpřístupňuje samotné streamy v reaktivních výpočtech pro pokročilejší případy použití.

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

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

console.log(added()); // zobrazí 12

Stream může záviset na libovolném počtu streamů a je zaručeno, že se aktualizuje atomicky. Například, pokud má stream A dva závislé streamy B a C a čtvrtý stream D je závislý na B i C, stream D se aktualizuje pouze jednou, pokud se změní hodnota A. To zaručuje, že callback pro stream D není nikdy volán s nestabilními hodnotami, například když má B novou hodnotu, ale C má starou hodnotu. Atomicita také přináší výkonnostní výhody tím, že se zbytečně nepřepočítávají downstreamy.

Můžete zabránit aktualizaci závislých streamů tím, že vrátíte speciální hodnotu stream.SKIP.

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

skipped.map(function () {
  // nikdy se nespustí
});

Stavy streamu ​

V daném okamžiku může být stream v jednom ze tří stavů: pending, active a ended.

Stav pending (čekající) ​

Streamy ve stavu pending lze vytvořit voláním stream() bez parametrů.

javascript
var pending = stream();

Pokud stream závisí na více než jednom rodičovském streamu a některý z jeho rodičovských streamů je ve stavu pending, je závislý stream také ve stavu pending a neaktualizuje svou hodnotu.

javascript
var a = stream(5);
var b = stream(); // čekající stream

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

console.log(added()); // zobrazí undefined

Ve výše uvedeném příkladu je added čekající stream, protože jeho rodič b je také čekající.

To platí také pro závislé streamy vytvořené pomocí stream.map:

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

console.log(doubled()); // zobrazí undefined, protože `doubled` je čekající

Stav active (aktivní) ​

Když stream obdrží hodnotu, je ve stavu active (pokud stream není ukončen).

javascript
var stream1 = stream('hello'); // stream1 je ve stavu active

var stream2 = stream(); // stream2 začíná jako čekající
stream2('world'); // pak se stane aktivním

Závislý stream s více rodiči je ve stavu active, pokud jsou všichni jeho rodiče aktivní.

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

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

Ve výše uvedeném příkladu je stream a aktivní, ale b je čekající. Nastavení b("world") by způsobilo, že se b stane aktivním, a proto by se greeting také stal aktivním a byl by aktualizován tak, aby měl hodnotu "hello world".

Stav ended (ukončený) ​

Stream může přestat ovlivňovat své závislé streamy voláním stream.end(true). Tím se efektivně odstraní spojení mezi streamem a jeho závislými streamy.

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

value.end(true); // nastavit na stav ended

value(5);

console.log(doubled());
// zobrazí undefined, protože `doubled` již nezávisí na `value`

Ukončené streamy si stále zachovávají sémantiku kontejneru stavu, tj. můžete je stále používat jako getter-settery, i když jsou ukončeny.

javascript
var value = stream(1);
value.end(true); // nastavit na stav ended

console.log(value(1)); // zobrazí 1

value(2);
console.log(value()); // zobrazí 2

Ukončení streamu může být užitečné v případech, kdy má stream omezenou životnost (například reakce na události mousemove pouze tehdy, když je prvek DOM přetahován, ale ne poté, co byl upuštěn).

Serializace streamů ​

Streamy implementují metodu .toJSON(). Když je stream předán jako argument do JSON.stringify(), je hodnota streamu serializována.

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

Streamy nespouštějí vykreslování ​

Na rozdíl od knihoven jako Knockout, streamy v Mithril.js nespouštějí automatické překreslování šablon. Překreslování se děje v reakci na obslužné rutiny událostí definované v zobrazeních komponent Mithril.js, změny tras nebo po vyřešení volání m.request.

Pokud je potřeba překreslování v reakci na jiné asynchronní události (např. setTimeout/setInterval, odběr websocketu, obslužná rutina událostí knihovny třetí strany atd.), měli byste ručně zavolat m.redraw().

Co je Fantasy Land ​

Fantasy Land specifikuje interoperabilitu běžných algebraických struktur. Jednoduše řečeno, to znamená, že knihovny, které vyhovují specifikacím Fantasy Land, lze použít k psaní generického funkčního kódu, který funguje bez ohledu na to, jak tyto knihovny implementují konstrukty.

Řekněme například, že chceme vytvořit generickou funkci nazvanou plusOne. Naivní implementace by vypadala takto:

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

Problém s touto implementací je, že ji lze použít pouze s číslem. Je však možné, že jakákoli logika, která vytváří hodnotu pro a, by mohla také vytvořit chybový stav (zabalený v Maybe nebo Either z knihovny jako Sanctuary nebo Ramda-Fantasy), nebo by to mohl být stream Mithril.js, stream Flyd atd. V ideálním případě bychom nechtěli psát podobnou verzi stejné funkce pro každý možný typ, který by a mohl mít, a nechtěli bychom opakovaně psát kód pro balení/rozbalování/zpracování chyb.

Zde může pomoci Fantasy Land. Přepišme tuto funkci z hlediska algebry Fantasy Land:

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

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

Nyní tato metoda funguje s jakýmkoli Funktorem kompatibilním s Fantasy Land, jako je R.Maybe, S.Either, stream atd.

Tento příklad se může zdát komplikovaný, ale je to kompromis ve složitosti: naivní implementace plusOne dává smysl, pokud máte jednoduchý systém a pouze inkrementujete čísla, ale implementace Fantasy Land se stává výkonnější, pokud máte velký systém s mnoha abstrakcemi obalů a opakovaně používanými algoritmy.

Při rozhodování, zda byste měli přijmout Fantasy Land, byste měli zvážit znalost funkcionálního programování vašeho týmu a být realističtí ohledně úrovně disciplíny, kterou se váš tým může zavázat k udržování kvality kódu (vs tlak na psaní nových funkcí a dodržování termínů). Funkcionální programování silně závisí na kompilaci, správě a zvládnutí velkého množství malých, přesně definovaných funkcí. Proto není vhodné pro týmy, které nemají zavedené postupy dokumentace a/nebo nemají zkušenosti s funkcionálně orientovanými jazyky.

Pager
Předchozí stránkacensor(object, extra)
Další stránkaNávod

Vydáno pod licencí MIT.

Copyright (c) 2024 Mithril Contributors

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

Vydáno pod licencí MIT.

Copyright (c) 2024 Mithril Contributors