Ottimizzazione JavaScript

Ramón Sacote

Scritto da Ramón Saquet

con Il passaggio degli utenti di dispositivi desktop ai dispositivi mobili, l’ottimizzazione delle pagine Web nel cliente diventa più interesse rispetto al passato, equivalente importanza alle ottimizzazioni sul server. Ed è rendere un elenco web veloce su dispositivi più lenti e con connessioni che, a seconda della copertura, potrebbero essere tagli cattivi o addirittura, non è un compito facile, ma è necessario, dal momento che hanno una velocità maggiore coinvolgerà Utenti più soddisfatti che ci visiteranno più spesso e posizionamento migliore nelle ricerche dal cellulare.

In questo articolo proverò alcuni dei punti in cui devi prestare maggiore attenzione al momento dell’ottimizzazione del JavaScript che funziona sul cliente. Prima di tutto vedremo come ottimizzare il download e la compilazione, e in secondo luogo, come ottimizzando la sua esecuzione in modo che la pagina abbia una buona performance. Comprensione per le prestazioni, la definizione fornita dal modello di rotaia Google. Questi acronimi significano:

  • Risposta dell’interfaccia in meno di 100 ms.
  • Animazioni con piena disegnata ogni 16ms che sono 60 fps o 60 immagini al secondo.
  • disabilitato: quando l’utente non interagisce con la pagina che funziona in background, non dovrebbe durare più di 50 ms.
  • caricamento: la pagina deve caricare a 1000 ms.

Questi tempi dobbiamo raggiungerli nel peggiore dei casi (quando il Web viene eseguito su un vecchio cellulare), con pochi processori e risorse di memoria.

Tempo di caricamento del web Rispetto al desktop.
Confronto del carico di un sito mobile e sul desktop ottenuto dalla database del report dell’utente del Chrome dell’utente del database pubblico. L’istogramma mostra il numero di utenti che hanno ottenuto ogni tempo di risposta. Come puoi vedere il picco massimo sul cellulare è 2.5sy sul desktop in 1,5s.

Avanti, in primo luogo, le azioni necessarie per ottimizzare lo scarico e la compilazione E, in secondo luogo, le azioni necessarie per ottimizzare l’esecuzione del codice, questa parte è più tecnica, ma non meno importante.

Azioni per ottimizzare il download e la compilazione del codice JavaScript

Cachiaio nel browser

Qui abbiamo due opzioni. Il primo è usare l’API della cache API JavaScript, da cui possiamo utilizzare installando un operatore di servizio. Il secondo è utilizzare la cache del protocollo HTTP. Se utilizziamo l’API della cache la nostra applicazione potrebbe avere la possibilità di funzionare in modalità disconnessa. Se utilizziamo la cache del protocollo HTTP, approssimativamente, dobbiamo configurarlo utilizzando il parametro di controllo della cache con valori pubblici e massimi di età, con un grande tempo di cache, ad esempio un anno. Successivamente, se vogliamo invalidare questa cache, cambieremo il nome nel file.

comprimere con Brotli Q11 e gzip

Quando si comprime il codice JavaScript, stiamo riducendo i bit che sono trasmessi dalla rete e, pertanto, il tempo di trasmissione, ma deve essere tenuto presente che stiamo aumentando il tempo di elaborazione sia sul server che sul client, dal momento che il primo deve comprimere il file e il secondo decomprimerlo. Possiamo salvare la prima volta se abbiamo una cache di file compressi sul server, ma il tempo di decompressione sul client più il tempo di trasmissione compresso, potrebbe essere maggiore del tempo di trasmissione del file decompresso, rendendo questa tecnica il download più lento. Questo accadrà solo con file molto piccoli e con elevate velocità di trasmissione. La velocità di trasmissione dell’utente non può sapere, ma può essere detto al nostro server che non comprende i file molto piccoli, ad esempio, dillo che non comprende i file meno di 280 byte. Nelle connessioni con alte velocità, oltre 100 MB / s, questo valore dovrebbe essere molto più alto, ma si tratta di ottimizzare per coloro che hanno collegamenti mobili con una piccola copertura, dove la perdita di prestazione è più pronunciata, sebbene in connessioni veloci vada un po ‘più lento.

Il nuovo algoritmo di compressione Brotli migliora la compressione rispetto a GZip del 17%. Se il browser invia, all’intestazione del protocollo HTTP, il valore “BR” all’interno del parametro codifica di acetto, ciò significherà che il server può inviare il file in formato Brotli anziché in Gzip.

Riduci al minimo

Consiste nell’utilizzo di uno strumento automatico per eliminare commenti, spazi, schede e sostituire le variabili per rendere il codice in meno di spazio.I file minimizzati dovrebbero essere affollati sul server o generati già ridotti al minimo quando li caricano, poiché se il server deve minimizzarli con ciascuna richiesta, avrà un negativo sulle prestazioni.

unifica il codice JavaScript

Questa è una tecnica di ottimizzazione che non è molto importante se il nostro sito Web funziona con HTTPS e HTTP2, poiché questo protocollo invia i file come se fossero solo uno, ma se il nostro sito web funziona con HTTP1.1 o speriamo di farlo Avere molti clienti con antichi browser che utilizzano questo protocollo, l’unificazione è necessaria per ottimizzare il download. Ma non è necessario passare e unificare tutto il codice Web nel file univoco, poiché se solo il codice di cui è necessario l’utente su ciascuna pagina viene inviato, i byte possono essere piuttosto ridotti. Per fare ciò, separeremo il codice di base necessario per l’intero portale di ciò che verrà eseguito su ogni singola pagina. In questo modo avremo due file JavaScript per ogni pagina, uno con le librerie di base che saranno comuni per tutte le pagine e un altro con il codice specifico della pagina. Con uno strumento come il webpack possiamo unificare e minimizzare questi due gruppi di file nel nostro progetto di sviluppo. Prova che lo strumento che usi per questo genererà le cosiddette “mappe sorgente”. Questi sono file .map associati all’intestazione del file finale e in cui vengono stabilite la relazione tra il codice ridotto e unificato e i file del codice sorgente effettivi. In questo modo, allora possiamo eseguire il debug del codice senza problemi.

L’opzione per unificare tutto in un singolo file più grande, ha il lato buono che è possibile schiaffeggiare tutto il codice JavaScript sul Web nel browser, acceso La prima visita e, nel prossimo carico, l’utente non dovrà scaricare tutto il codice JavaScript. Quindi questa opzione lo consiglio solo se il risparmio di byte è praticamente spregevole rispetto alla tecnica precedente e abbiamo un basso tasso di rimbalzo.

Segna il JavaScript come Asynchronous

Dobbiamo Includi il JavaScript come segue:

<script async src="/codigo.js" />

In questo modo impediamo l’aspetto dell’etichetta dello script che blocca la fase del documento della pagina della pagina.

Non utilizzare JavaScript incorporato in pagina

Quando si utilizza il tag script per incorporare il codice sulla pagina, la costruzione DOM è anche bloccata e ancora di più se viene utilizzata la funzione Document.Write () . In altre parole, questo è proibito:

< script Document.Write (“Hello World!”) ; < / Script >

Carica il JavaScript all’intestazione della pagina con ASYNC

Prima di avere il tag async, si consiglia di mettere tutti i tag di script nella parte inferiore della pagina per evitare di bloccare la costruzione di esso. Questo non è più necessario, infatti è meglio che sia all’altezza dell’etichetta <, in modo che il JavaScript inizi a scaricare, analizzare e compilare il prima possibile, poiché queste fasi sono quelli che stanno per più prendere. Se questo attributo non viene utilizzato, il JavaScript deve essere alla fine.

Elimina JavaScript che non viene utilizzata

A questo punto non stiamo solo ridendo il tempo di trasmissione, ma anche il Tempo che ti porta al browser analizzare e compilare il codice. Per fare ciò, dobbiamo prendere in considerazione i seguenti punti:

  • Se viene rilevato che una funzionalità non viene utilizzata dagli utenti, possiamo cancellarlo con tutto il suo codice JavaScript associato, in modo che il il Web si carica più velocemente e gli utenti lo apprezzeranno.
  • Potremmo essere inclusi anche da qualche libreria che non è necessaria o abbiamo biblioteche che offrono alcune funzionalità da cui abbiamo già nativamente in tutti i browser, non c’è bisogno Per utilizzare un codice aggiuntivo e più velocemente.
  • Infine, se vogliamo ottimizzare la fine, indipendentemente dal tempo che indossi, dovremmo eliminare il codice che non stiamo usando all’interno delle librerie. Ma non lo consiglio, perché non sappiamo mai quando è necessario essere necessari.

Postpone il carico JavaScript che non è necessario:

dovrebbe essere Fatto con quelle funzionalità che non sono necessarie per l’iniziale disegnato della pagina. Sono funzionalità per le quali l’utente deve eseguire una determinata azione per eseguirlo. In questo modo evitiamo di caricare e compilare il codice JavaScript che ritarderebbe la visualizzazione iniziale. Una volta che la pagina è completamente carica, possiamo avviare il carico di queste funzionalità in modo che siano immediatamente disponibili quando l’utente inizia ad interagire.Google nel modello della ferrovia raccomanda di essere effettuato il carico posticipato in blocchi di 50 ms in modo che non influenzi l’interazione dell’utente con la pagina. Se l’utente interagisce con una funzionalità che non è stata ancora caricata, dobbiamo caricarla in quel momento.

Azioni per ottimizzare l’esecuzione del codice JavaScript

Evitare di usare troppa memoria

Non puoi dire quanta memoria sarà troppo, ma puoi dire che dovremmo sempre cercare di non usare più del necessario, perché non sappiamo quanto memoria avrà il dispositivo che eseguirà la rete. Quando viene eseguito il Browser Garbage Collector, è per l’esecuzione di JavaScript, e ciò accade ogni volta che il nostro codice richiede il browser per prenotare una nuova memoria. Se ciò accade frequentemente, la pagina verrà eseguita lentamente.

Nella scheda “Memoria” degli strumenti per sviluppatori di Chrome, possiamo vedere la memoria occupata da ciascuna funzione JavaScript:

Memoria riservata tramite funzione javascript.
memoria riservata dalla funzione

Evitare le perdite di memoria

Se abbiamo una perdita di memoria in un ciclo, la pagina riservrà sempre più memoria che occupa tutto il dispositivo disponibile e renderà tutto sempre più lento. Questo fallimento è solitamente dato in caroselli e cursori di immagini.

In Chrome possiamo analizzare se il nostro sito Web ha perdite di memoria con la registrazione di una timeline sulla scheda Performance degli strumenti di sviluppo:

Display perdite di memoria sulla scheda Prestazioni Chrome Google.
Questo è l’aspetto che ha una perdita di memoria nella scheda “Performance” di Google Chrome Possiamo osservare una crescita costante dei nodi JS Dom e Heap.

Di solito perdite di memoria viene fornito dai pezzi di SDU che vengono eliminati dalla pagina ma che hanno eliminato dalla pagina ma che hanno eliminato dalla pagina Qualsiasi variabile che li fa riferimento e, pertanto, il raccoglitore della spazzatura non può eliminarli e non capire come la portata delle variabili e chiusure nel lavoro javascript.

Dom Dom Doming Trees.
Dom Dom Dom Trees (Dom Tree distaccato) che occupano la memoria perché ci sono variabili che li fanno riferimento.

USA Web operai quando è necessario eseguire il codice Hai bisogno di un sacco di runtime

Tutti i processori oggi sono multi-cella e multi-core, ma JavaScript è stato tradizionalmente un linguaggio monocoloso e, sebbene abbia timer, questi vengono eseguiti nello stesso filo di esecuzione, in cui, Inoltre, viene eseguita l’interazione con l’interfaccia, quindi mentre JavaScript è in esecuzione l’interfaccia è bloccata e ci vogliono più di 50 ms sarà evidente. I lavoratori Web e i lavoratori del servizio ci portano l’esecuzione multi-fan a JavaScript, anche se non consentono l’accesso diretto alla domenica, quindi dovremo pensare a come ritardare l’accesso a questo, al fine di applicare i lavoratori Web nei casi che noi avere un codice che pomeriggio più di 50 ms da eseguire.

utilizzando l’API di recupero (AJAX)

L’uso dell’API di recupero o AJAX è anche un buon modo per l’utente a Percepire un tempo di carico più rapido, ma non dovremmo usarlo nel carico iniziale, ma nella navigazione successiva e in un modo che è indicizzabile. Per fare ciò, il modo migliore per implementarlo è utilizzare un framework che utilizza JavaScript universale.

prioritizza l’accesso a variabili locali

JavaScript prima vedi se la variabile esiste localmente e segue la ricerca della variabile Nelle aree superiori, le ultime variabili globali. JavaScript Access Variables locali più veloce perché non è necessario cercare la variabile in ambiti superiori per trovarlo, quindi è una buona strategia che salva in variabili locali quelle variabili di un’area più alta di quanto accetteremo più volte e, in aggiunta, Non creare nuove aree con chiusure o con le dichiarazioni di cattura con e provano, senza di esso necessario.

Se si accede a un oggetto DOM più volte per salvarlo in una variabile locale

al dom è lento. Quindi, se stessimo leggere il contenuto di un oggetto più volte, meglio salvarlo in una variabile locale, quindi il JavaScript non dovrà cercare l’elemento al sole ogni volta che vuoi accedere al suo contenuto. Ma prestare attenzione, se si tiene un pezzo di DOM in una variabile che hai più tardi dalla pagina e non usi più, prova quindi assegnare a “null” la variabile in cui l’hai salvato in modo da non causare una perdita di memoria .

gruppo e minimizzare le letture del DOM e CSSOM e gli script

Quando il browser disegna una pagina esegue il percorso di rappresentazione critica che segue i seguenti passaggi nella prima carica:

  1. L’HTML viene ricevuto.
  2. inizia a costruire il DOM.
  3. Mentre il DOM è stato costruito, vengono richieste risorse esterne (CSS e JS).
  4. viene costruito il CCSOM (DOM Miscela e il CSS).
  5. L’albero di rappresentazione è stato creato (sono le parti del CSSOM che verranno disegnate).
  6. Dall’albero di rappresentazione viene calcolato la geometria di ciascuna parte visibile dell’albero in uno strato. Questa fase è chiamata layout o reflow.
  7. Nella fase finale della pittura, gli strati del passaggio 6 sono dipinti e stanno compendendo uno sopra un altro per mostrare la pagina all’utente.
  8. Se hai finito di compilare il JavaScript, funziona (in realtà, questo passaggio potrebbe verificarsi in qualsiasi momento dopo il passaggio 3, essere meglio il più presto possibile).
  9. Se nel passaggio precedente le forze del codice JavaScript Per ripetere parte del DOM o del CSSOM restituiamo diversi passaggi dietro che verrà eseguito fino al punto 7.
Costruzione dell'albero di rendering o albero di rendering.
Costruzione dell’albero di rappresentazione

Sebbene i browser stiano incollando le modifiche del albero di rappresentazione e decidere quando fare la riditazione, se abbiamo un ciclo in cui leggiamo il DOM e / o il CSSOM e lo modifichiamo e lo modifichino nella riga successiva, il browser potrebbe vedere f Estado per eseguire il reflow o ridipingere la pagina più volte, specialmente se la seguente lettura dipende dalla scrittura precedente. Ecco perché è consigliato:

  • Separare tutte le letture in un loop separato e rendono tutti gli scritti contemporaneamente con la proprietà CSstext se è il CSSOM o INNERHTML se è il SUNDER, così Il browser dovrai lanciare solo una riditazione.
  • Se le letture dipendono dalle scritture precedenti, cercano un modo per riscrivere l’algoritmo in modo che questo non sia così.
  • Se Non hai scelta applicare molte modifiche a un elemento della domenica, portalo fuori dalla domenica, rendono le modifiche e restituirlo per introdurre dove si trovava.
  • su Google Chrome, possiamo analizzare ciò che accade sulla rotta di rappresentazione critica con lo strumento del faro nella scheda “Audit” o sulla scheda “Prestazioni” registrando ciò che accade mentre la pagina è caricata.
Analisi delle prestazioni dello strumento del faro.
in questa analisi delle prestazioni del faro della home page di Google , possiamo vedere quali risorse bloccano la rotta di rappresentazione critica.

Utilizzare la funzione RESTANIMATIONFRAME (CALLBACK) in Animazioni e gli effetti dipendono dallo Scroll

La funzione RESTOSTANIMATIONFRAME () (), fa sì che la funzione sia passata come parametro non causa una riditazione, fino al prossimo programmato. Questo, oltre a evitare inutili ridipenti, ha l’effetto che le animazioni si fermano mentre l’utente è in un’altra scheda, salvando la batteria della CPU e del dispositivo.

Gli effetti che dipendono dallo scorrimento sono i seguenti perché il seguente DOM Proprietà Forza un reflow (passaggio 7 del punto precedente) quando si accede a loro:

offsetTop, offsetLeft, offsetWidth, offsetHeightscrollTop, scrollLeft, scrollWidth, scrollHeightclientTop, clientLeft, clientWidth, clientHeightgetComputedStyle() (currentStyle en IE)

Se oltre a accedere a una di queste proprietà, quindi in base a loro, Dipingiamo un banner o un menu che ti seguiamo spostando il rotolo o un effetto di scorrimento, la ridiping di più strati ogni volta che si sposta il rotolo, influenzando negativamente il tempo di risposta dell’interfaccia, con il quale possiamo avere un rotolo che sta dando il salto invece di scivolare delicatamente. Pertanto, con questi effetti, l’ultima posizione del rotolo nell’evento OnScroll deve essere salvata in una variabile globale e, dopo aver utilizzato la funzione RESOSTANIMATIONFRAME () solo se l’animazione precedente è finita.

Se ci sono Molti eventi simili AGRIC IT

Se si dispone di 300 pulsanti che quando fai clic su rendere praticamente lo stesso, possiamo assegnare un evento all’elemento principale dei pulsanti 300 invece di assegnare 300 eventi a ciascuno di essi. Facendo clic su un pulsante, l’evento “bolla” per il genitore e da questo possiamo sapere quale pulsante ha fatto clic e modifica il comportamento di conseguenza.

Attenzione di eventi che scattano più volte seguiti

Eventi come OnMouseMove o OnScroll, riprendere più volte in fila mentre l’azione viene eseguita. Quindi prova a controllare che il codice associato non esegue più volte rispetto ai necessari, poiché questo è un errore abbastanza comune.

Evitare l’esecuzione del codice con il codice con EVAL (), FUNCTION (), SettimeOut () e SetInterval ()

Il fatto di introdurre il codice in un letterale da analizzare e compilato Durante l’esecuzione del resto del codice è abbastanza lento, ad esempio: Eval (“C = A + B”); Puoi sempre rifare il programma per evitare di doverlo fare.

Implementare le ottimizzazioni che si applichi in qualsiasi altro linguaggio di programmazione

  • Utilizzare sempre gli algoritmi con la minima complessità computazionale o Complessità ciclomatica per il compito da risolvere.
  • utilizza le strutture di dati ottimali per ottenere il punto precedente.
  • Riscrivi l’algoritmo per ottenere lo stesso risultato con meno calcoli.
  • Evita le chiamate ricorsive, modificando l’algoritmo da uno equivalente che fa uso di uno stack.
  • Effettuare una funzione con un costo elevato e le chiamate ripetute lungo diversi blocchi di codice salvano in memoria il risultato per il risultato del risultato Prossima chiamata.
  • Metti i calcoli e le chiamate alle funzioni ripetute in variabili.
  • Quando si cammina un anello, memorizza la dimensione del ciclo in una variabile per primo, per evitare di calcolarlo di nuovo , nella sua condizione di completamento, in ogni iterazione.
  • Factorizar e semplifica le formule matematiche.
  • sostituisce i calcoli che non dipendono dalle variabili da costanti e lascia il calcolo commentato.
  • utilizza invece gli array di ricerca: servono ad ottenere un valore in base a un altro invece Usando un blocco dell’interruttore.
  • Afferrano sempre le condizioni più probabilità di sfruttare l’esecuzione speculativa del processore, poiché quindi la previsione dei salti fallirà meno.
  • Semplifica le espressioni booleane Con le regole della logica booleana o meglio ancora con le mappe di Karnaugh.
  • utilizza gli operatori a livello di bit quando è possibile utilizzarli per sostituire alcune operazioni, poiché questi operatori utilizzano meno cicli del processore. Usarli richiede che l’aritmetico binario sappia, ad esempio: essere il valore XA di un’intera variabile, possiamo mettere “y = x 1 ” invece di “y = x / 2;” o “y = x & 0xff;” Invece di “y = x% 256”.

Questi sono alcuni dei miei preferiti, il più importante è il primo tre e il più studio e la pratica richiedono. Quest’ultima sono micro-ottimizzazioni che valgono solo la pena se si effettua il fatto mentre scrivi il codice o se è qualcosa di computabile molto costoso come editor video o un videogioco, anche se in quei casi sarai migliore del webassembly invece di JavaScript .

Strumenti per rilevare i problemi

Abbiamo già visto diversi. Di tutti loro, il faro è il più facile da interpretare, poiché ci dà semplicemente una serie di punti da migliorare, come può anche darci gli intuizioni di Google Pagunghespeed o, molti altri, come GTmetrix. In Chrome possiamo anche utilizzare, nell’opzione “Più strumenti” nel menu principale, il Task Manager, per visualizzare la memoria e la CPU utilizzata da ciascuna scheda. Per un’analisi ancora più tecnica, abbiamo gli strumenti per gli sviluppatori di Firefox e Google Chrome, dove abbiamo la scheda chiamata “Performance” e che ci consente di analizzare i tempi di ogni fase, perdite di memoria, ecc. Vediamo un esempio:

Analisi di prestazioni Chrome di Google.
in Google Chrome Performance Analysis, nello strumento Menu Ci consente di simulare una CPU e una rete più lenta, e in esso vediamo, tra le altre cose, le immagini o le tabelle al secondo (ricordiamo che deve essere inferiore a 16 ms) e le fasi della rotta di rappresentazione critica con i colori: In blu il tempo di ricarica dei file, in giallo il tempo di esecuzione degli script, in viola il tempo di costruzione dell’albero di rappresentazione (compreso i riflessi o la costruzione del layout) e in verde il tempo di pittura. Inoltre, il tempo che ha portato a dipingere ogni fotogramma appare e poiché questo è stato.

Tutte le informazioni che vediamo sopra possono essere registrate mentre la pagina È caricato, corriamo un’azione o fai scorrere. Quindi possiamo ingrandire a una parte del grafico per vederlo in dettaglio e, se come in questo caso, cosa richiede il massimo è l’esecuzione di JavaScript, possiamo distribuire la sezione principale e fare clic su Top degli script che richiedono più tempo . Quindi lo strumento ci mostrerà in dettaglio nella scheda Bottom-up in quanto influenza il JavaScript a ciascuna fase del percorso di rappresentazione critico e nella scheda Riepilogo, indicherà con un avviso se ha rilevato un problema di prestazione in JavaScript. Crething in cima al file che indica, ci ci vorrà specificamente alla linea che produce il ritardo.

Riepilogo dello strumento DevTools con preavviso PROBLEMA AVVISO. AVVERTENZA DELLA TAB SINTESI DEGLI STRUMENTI DI PRESTAZIONE

Infine, per anche per l’analisi più fine, è consigliabile utilizzare API tempistica di navigazione JavaScript che ci consente di misurare questa parte di ogni parte del nostro codice dal nostro codice dal nostro codice programmazione stessa.

Raccomandazioni finali

Come vedi, l’ottimizzazione di Javascript non è un compito facile e trasporta un processo di analisi e ottimizzazione del lavoro che può facilmente superare il budget destinato allo sviluppo che abbiamo avuto inizialmente pensato. Pertanto, ci sono pochi siti Web, plug-in e argomenti più famosi per i soliti manager dei contenuti che presentano molti dei problemi che ho elencato.

Se il tuo sito web presenta questi problemi, cerca di risolvere quelli che un maggiore impatto ha il Performance e cercare ogni volta che le ottimizzazioni non influenzano la manutenzione e la qualità del codice. Ecco perché non raccomando l’uso di tecniche di ottimizzazione più estreme, come la rimozione delle chiamate alle funzioni sostituendole dal codice che chiamano, il srotolazione dei loop o l’uso della stessa variabile per tutto, in modo che sia stato Caching o dai record del processore, poiché sono tecniche che sporcheranno il codice e, nella compilazione al runtime JavaScript, alcuni di essi sono applicati. Quindi ricorda:

le prestazioni non è un requisito che non deve mai essere superiore alla facilità di rilevare errori e aggiungere funzionalità.

hai visto

contattaci se vuoi che ti aiuti a migliorare la tua visibilità online. Parlaci di ciò che il tuo progetto sta andando e presentiamo una proposta personalizzata per le esigenze della tua attività.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *