Skip to content
Mithril.js 2
Main Navigation GuidaAPI

Italiano

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

Italiano

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

Aspetto

Sidebar Navigation

API

API principale

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)

API opzionale

stream()

Guida

In questa pagina

stream() ​

Descrizione ​

Uno stream è una struttura dati reattiva, simile alle celle di un foglio di calcolo.

Ad esempio, in un foglio di calcolo, se A1 = B1 + C1, modificando il valore di B1 o C1 il valore di A1 cambia automaticamente.

Allo stesso modo, puoi definire uno stream in modo che dipenda da altri stream: la modifica del valore di uno aggiornerà automaticamente l'altro. Questo è utile quando hai calcoli complessi e vuoi eseguirli solo quando necessario, invece che, ad esempio, ad ogni ridisegno.

Gli stream NON sono inclusi nella distribuzione principale di Mithril.js. Per includere il modulo Stream, usa:

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

Puoi anche scaricare il modulo direttamente se il tuo ambiente non supporta un sistema di bundling.

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

Quando viene caricata direttamente con un tag <script> (invece di essere richiesto), la libreria stream sarà esposta come window.m.stream. Se window.m è già definito (ad esempio, perché usi anche lo script principale di Mithril.js), si attaccherà all'oggetto esistente. Altrimenti crea un nuovo window.m. Se desideri utilizzare gli stream insieme a Mithril.js tramite tag script, dovresti includere Mithril.js nella tua pagina prima di mithril/stream, perché altrimenti mithril sovrascriverà l'oggetto window.m definito da mithril/stream. Questo non è un problema quando le librerie vengono utilizzate come moduli CommonJS (usando require(...)).

Firma ​

Crea uno stream.

stream = Stream(value)

ArgomentoTipoRichiestoDescrizione
valueanyNoSe presente, imposta il valore iniziale dello stream.
restituisceStreamRestituisce uno stream.

Come leggere le firme

Membri statici ​

Stream.combine ​

Crea uno stream calcolato che si aggiorna in modo reattivo quando uno qualsiasi degli stream da cui dipende viene aggiornato. Vedi combinazione di stream.

stream = Stream.combine(combiner, streams)

ArgomentoTipoRichiestoDescrizione
combiner(Stream..., Array) -> anySìVedi l'argomento combiner.
streamsArray<Stream>SìUn array di stream da combinare.
restituisceStreamRestituisce uno stream.

Come leggere le firme

combiner ​

Specifica come viene generato il valore dello stream calcolato. Vedi combinazione di stream.

any = combiner(streams..., changed)

ArgomentoTipoRichiestoDescrizione
streams...splat di StreamsNoElenco di zero o più stream che corrispondono agli stream passati come secondo argomento a stream.combine.
changedArray<Stream>SìElenco degli stream che sono stati modificati da un aggiornamento.
restituisceanyRestituisce un valore calcolato.

Come leggere le firme

Stream.merge ​

Crea uno stream il cui valore è un array contenente i valori di un altro array di stream.

stream = Stream.merge(streams)

ArgomentoTipoRichiestoDescrizione
streamsArray<Stream>SìUn array di stream.
restituisceStreamRestituisce uno stream il cui valore è un array di valori degli stream di input.

Come leggere le firme

Stream.scan ​

Crea un nuovo stream con i risultati della funzione chiamata su ogni valore dello stream, utilizzando un accumulatore e il valore in ingresso.

Nota che puoi impedire l'aggiornamento degli stream dipendenti restituendo il valore speciale stream.SKIP.

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

ArgomentoTipoRichiestoDescrizione
fn(accumulator, value) -> result | SKIPSìUna funzione che accetta un accumulatore e un valore, e restituisce un nuovo valore accumulatore dello stesso tipo.
accumulatoranySìIl valore iniziale per l'accumulatore.
streamStreamSìLo stream contenente i valori.
restituisceStreamRestituisce un nuovo stream contenente il risultato.

Come leggere le firme

Stream.scanMerge ​

Prende un array di coppie stream/funzione scan e unisce tutti quegli stream usando le funzioni fornite in un singolo stream.

stream = Stream.scanMerge(pairs, accumulator)

ArgomentoTipoRichiestoDescrizione
pairsArray<[Stream, (accumulator, value) -> value]>SìUn array di tuple stream/funzione scan.
accumulatoranySìIl valore iniziale per l'accumulatore.
restituisceStreamRestituisce un nuovo stream contenente il risultato.

Come leggere le firme

Stream.lift ​

Crea uno stream calcolato che si aggiorna in modo reattivo quando uno qualsiasi degli stream da cui dipende viene aggiornato. Vedi combinazione di stream. A differenza di combine, gli stream di input sono passati come un numero variabile di argomenti (invece di un array) e la callback riceve i valori degli stream invece degli stream stessi. Non c'è un parametro changed. Questa è generalmente una funzione più intuitiva per le applicazioni rispetto a combine.

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

ArgomentoTipoRichiestoDescrizione
lifter(any...) -> anySìVedi l'argomento lifter.
streams...lista di StreamsSìStream da combinare.
restituisceStreamRestituisce uno stream.

Come leggere le firme

lifter ​

Specifica come viene generato il valore dello stream calcolato. Vedi combinazione di stream.

any = lifter(streams...)

ArgomentoTipoRichiestoDescrizione
streams...splat di StreamsNoElenco di zero o più valori che corrispondono ai valori degli stream passati a stream.lift.
restituisceanyRestituisce un valore calcolato.

Come leggere le firme

Stream.SKIP ​

Un valore speciale che può essere restituito dalle callback degli stream per saltare l'esecuzione degli stream dipendenti.

Stream["fantasy-land/of"] ​

Questo metodo è funzionalmente identico a stream. Esiste per conformarsi alla specifica Applicative di Fantasy Land. Per maggiori informazioni, vedi la sezione Cos'è Fantasy Land.

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

ArgomentoTipoRichiestoDescrizione
valueanyNoSe presente, imposta il valore iniziale dello stream.
restituisceStreamRestituisce uno stream.

Membri dell'istanza ​

stream.map ​

Crea uno stream dipendente il cui valore è impostato sul risultato della funzione di callback. Questo metodo è un alias di stream["fantasy-land/map"].

dependentStream = stream().map(callback)

ArgomentoTipoRichiestoDescrizione
callbackany -> anySìUna callback il cui valore di ritorno diventa il valore dello stream.
restituisceStreamRestituisce uno stream.

Come leggere le firme

stream.end ​

Uno stream co-dipendente che annulla la registrazione degli stream dipendenti quando impostato su true. Vedi stato ended.

endStream = stream().end

stream["fantasy-land/of"] ​

Questo metodo è funzionalmente identico a stream. Esiste per conformarsi alla specifica Applicative di Fantasy Land. Per maggiori informazioni, vedi la sezione Cos'è Fantasy Land.

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

ArgomentoTipoRichiestoDescrizione
valueanyNoSe presente, imposta il valore iniziale dello stream.
restituisceStreamRestituisce uno stream.

stream["fantasy-land/map"] ​

Crea uno stream dipendente il cui valore è impostato sul risultato della funzione di callback. Vedi concatenamento di stream.

Questo metodo esiste per conformarsi alla specifica Applicative di Fantasy Land. Per maggiori informazioni, vedi la sezione Cos'è Fantasy Land.

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

ArgomentoTipoRichiestoDescrizione
callbackany -> anySìUna callback il cui valore di ritorno diventa il valore dello stream.
restituisceStreamRestituisce uno stream.

Come leggere le firme

stream["fantasy-land/ap"] ​

Il nome di questo metodo sta per apply (applica). Se uno stream a ha una funzione come suo valore, un altro stream b può usarlo come argomento per b.ap(a). Chiamare ap chiamerà la funzione con il valore dello stream b come suo argomento, e restituirà un altro stream il cui valore è il risultato della chiamata di funzione. Questo metodo esiste per conformarsi alla specifica Applicative di Fantasy Land. Per maggiori informazioni, vedi la sezione Cos'è Fantasy Land.

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

ArgomentoTipoRichiestoDescrizione
applyStreamSìUno stream che contiene una funzione.
restituisceStreamRestituisce uno stream.

Utilizzo base ​

Gli stream non sono inclusi nella distribuzione principale di Mithril.js. Per includerli in un progetto, richiedi il modulo:

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

Stream come variabili ​

stream() restituisce uno stream. A livello più elementare, uno stream funziona in modo simile a una variabile o a una proprietà getter-setter: può contenere uno stato, che può essere modificato.

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

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

La differenza principale è che uno stream è una funzione, e quindi può essere composto in funzioni di ordine superiore.

javascript
var users = stream();

// request users from a server using the fetch API
fetch('/api/users')
  .then(function (response) {
    return response.json();
  })
  .then(users);

Nell'esempio sopra, lo stream users viene popolato con i dati di risposta quando la richiesta viene completata.

Binding bidirezionali ​

Gli stream possono anche essere aggiornati tramite callback di eventi e simili.

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

// un binding bidirezionale allo stream
m('input', {
  oninput: function (e) {
    user(e.target.value);
  },
  value: user(),
});

Nell'esempio sopra, quando l'utente inserisce un valore nell'input, lo stream user viene aggiornato con il valore del campo di input.

Proprietà calcolate ​

Gli stream sono utili per implementare proprietà calcolate.

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

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

Nell'esempio sopra, il valore di slug viene calcolato quando title viene aggiornato, non quando slug viene letto.

È possibile calcolare proprietà basate anche su più 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()); // stampa "John Doe"

firstName('Mary');

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

Le proprietà calcolate in Mithril.js vengono aggiornate in modo atomico: gli stream che dipendono da più stream non verranno mai chiamati più di una volta per aggiornamento del valore, non importa quanto sia complesso il grafico di dipendenza della proprietà calcolata.

Concatenamento di stream ​

Gli stream possono essere concatenati utilizzando il metodo map. Uno stream concatenato è anche noto come stream dipendente.

javascript
// stream genitore
var value = stream(1);

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

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

Gli stream dipendenti sono reattivi: i loro valori vengono aggiornati ogni volta che il valore del loro stream genitore viene aggiornato. Questo accade indipendentemente dal fatto che lo stream dipendente sia stato creato prima o dopo che il valore dello stream genitore sia stato impostato.

Puoi impedire l'aggiornamento degli stream dipendenti restituendo il valore speciale stream.SKIP.

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

skipped.map(function () {
  // non viene mai eseguito
});

Combinazione di stream ​

Gli stream possono dipendere da più di uno stream genitore. Questi tipi di stream possono essere creati utilizzando 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()); // stampa "hello world"

Oppure puoi usare la funzione helper 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()); // stampa "hello world"

Esiste anche un metodo di livello inferiore chiamato stream.combine() che espone gli stream stessi nei calcoli reattivi per casi d'uso più avanzati.

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

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

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

Uno stream può dipendere da un numero qualsiasi di stream ed è garantito che si aggiorni atomicamente. Ad esempio, se uno stream A ha due stream dipendenti B e C, e un quarto stream D dipende sia da B che da C, lo stream D si aggiornerà solo una volta se il valore di A cambia. Questo garantisce che la callback per lo stream D non venga mai chiamata con valori inconsistenti, ad esempio quando B ha un nuovo valore ma C ha il vecchio valore. L'atomicità porta anche vantaggi in termini di prestazioni, evitando ricalcoli inutili degli stream dipendenti.

Puoi impedire l'aggiornamento degli stream dipendenti restituendo il valore speciale stream.SKIP.

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

skipped.map(function () {
  // non viene mai eseguito
});

Stati dello stream ​

In un dato momento, uno stream può trovarsi in uno dei tre stati: pending (in sospeso), active (attivo) ed ended (terminato).

Stato pending ​

Gli stream in sospeso possono essere creati chiamando stream() senza parametri.

javascript
var pending = stream();

Se uno stream dipende da più di uno stream e uno qualsiasi dei suoi stream genitori è in uno stato in sospeso, anche lo stream dipendente è in uno stato in sospeso e non aggiorna il suo valore.

javascript
var a = stream(5);
var b = stream(); // pending stream

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

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

Nell'esempio sopra, added è uno stream in stato di attesa, perché il suo genitore b è anch'esso in sospeso.

Questo vale anche per gli stream dipendenti creati tramite stream.map:

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

console.log(doubled()); // stampa undefined perché `doubled` è in sospeso

Stato active ​

Quando uno stream riceve un valore, diventa attivo (a meno che lo stream non sia terminato).

javascript
var stream1 = stream('hello'); // stream1 è attivo

var stream2 = stream(); // stream2 inizia in sospeso
stream2('world'); // poi diventa attivo

Uno stream dipendente con più genitori diventa attivo se tutti i suoi genitori sono attivi.

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

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

Nell'esempio sopra, lo stream a è attivo, ma b è in sospeso. Impostare b("world") farebbe sì che b diventasse attivo, e quindi anche greeting diventerebbe attivo e verrebbe aggiornato per avere il valore "hello world".

Stato ended ​

Uno stream può smettere di influenzare i suoi stream dipendenti chiamando stream.end(true). Questo rimuove la connessione tra uno stream e i suoi stream dipendenti.

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

value.end(true); // impostato allo stato ended

value(5);

console.log(doubled());
// stampa undefined perché `doubled` non dipende più da `value`

Gli stream terminati mantengono comunque una semantica di contenitore di stato, cioè puoi ancora usarli come getter-setter, anche dopo che sono stati terminati.

javascript
var value = stream(1);
value.end(true); // impostato allo stato ended

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

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

Terminare uno stream può essere utile nei casi in cui uno stream ha una durata limitata (ad esempio, reagire agli eventi mousemove solo mentre un elemento DOM viene trascinato, ma non dopo che è stato rilasciato).

Serializzazione di stream ​

Gli stream implementano un metodo .toJSON(). Quando uno stream viene passato come argomento a JSON.stringify(), il valore dello stream viene serializzato.

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

Gli stream non attivano il rendering ​

A differenza di librerie come Knockout, gli stream di Mithril.js non attivano il re-rendering dei template. Il ridisegno avviene in risposta ai gestori di eventi definiti nelle viste dei componenti di Mithril.js, alle modifiche di rotta oppure dopo che le chiamate a m.request sono state completate.

Se desideri il ridisegno in risposta ad altri eventi asincroni (ad esempio setTimeout/setInterval, sottoscrizione websocket, gestore di eventi di librerie di terze parti, ecc.), è necessario chiamare manualmente m.redraw().

Cos'è Fantasy Land ​

Fantasy Land specifica l'interoperabilità delle strutture algebriche comuni. In parole povere, ciò significa che le librerie conformi alle specifiche di Fantasy Land possono essere utilizzate per scrivere codice generico in stile funzionale, che funziona indipendentemente da come queste librerie implementano i costrutti.

Ad esempio, supponiamo di voler creare una funzione generica chiamata plusOne.

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

Il problema con questa implementazione è che può essere utilizzata solo con numeri. Tuttavia, è possibile che qualsiasi logica che produce un valore per a potrebbe anche produrre uno stato di errore (avvolto in un Maybe o un Either da una libreria come Sanctuary o Ramda-Fantasy), oppure potrebbe essere uno stream di Mithril.js, uno stream di Flyd, ecc. Idealmente, non vorremmo scrivere una versione simile della stessa funzione per ogni possibile tipo che a potrebbe avere e non vorremmo scrivere ripetutamente codice di wrapping, unwrapping e gestione degli errori.

È qui che Fantasy Land può essere utile. Riscriviamo quella funzione in termini di un'algebra di Fantasy Land:

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

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

Ora questo metodo funziona con qualsiasi Functor conforme a Fantasy Land, come R.Maybe, S.Either, stream, ecc.

Questo esempio potrebbe sembrare complesso, ma è un compromesso in termini di complessità: l'implementazione naive di plusOne ha senso se hai un sistema semplice e incrementi solo numeri, ma l'implementazione di Fantasy Land diventa più potente se hai un sistema grande con molte astrazioni di wrapper e algoritmi riutilizzati.

Quando decidi se adottare Fantasy Land, dovresti considerare la familiarità del tuo team con la programmazione funzionale ed essere realistico riguardo al livello di disciplina che il tuo team può impegnarsi a mantenere la qualità del codice (rispetto alla pressione di scrivere nuove funzionalità e rispettare le scadenze). La programmazione in stile funzionale dipende fortemente dalla compilazione, dalla cura e dalla padronanza di un ampio set di funzioni piccole e definite con precisione, e quindi non è adatta ai team che non hanno solide pratiche di documentazione e/o mancano di esperienza in linguaggi orientati alla funzionalità.

Pager
Pagina precedentecensor(object, extra)
Pagina successivaGuida

Rilasciato sotto la licenza MIT.

Copyright (c) 2024 Mithril Contributors

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

Rilasciato sotto la licenza MIT.

Copyright (c) 2024 Mithril Contributors