ఎవరూ చర్చించని DOM అడ్డంకి
పది వేల లాగ్ ఎంట్రీలను పొందుపరిచే ఒక సపోర్ట్ డ్యాష్బోర్డ్ను ఊహించుకోండి. లేదా ప్రతి కాంటాక్ట్ను ఒకే స్క్రోల్ చేయగల టేబుల్లో ప్రదర్శించడానికి ప్రయత్నిస్తున్న ఒక CRMని ఊహించుకోండి. Reactలో, దీనిని నిర్మించడానికి రాసే కోడ్ చూడటానికి చాలా సాధారణంగా కనిపిస్తుంది. మీరు ఒక అర్రే (array) పై మ్యాప్ (map) చేసి, కొంత JSXని రిటర్న్ చేస్తారు మరియు ఫ్రేమ్వర్క్ను దాని పని చేయనిస్తారు. డెవలప్మెంట్లో వంద వరుసలతో అంతా బాగానే పనిచేస్తుంది. కానీ ప్రొడక్షన్ డేటా రాగానే, పేజీ చాలా నెమ్మదిగా (sludge లాగా) మారిపోతుంది.
బ్రౌజర్ బద్ధకంగా వ్యవహరించడం లేదు. మీరు అడిగినట్లే అది చేస్తోంది, అదే సమస్య. ప్రతి వరుస ఒక DOM నోడ్గా మారుతుంది. ప్రతి నోడ్కు స్టైలింగ్, లేఅవుట్, పెయింటింగ్ మరియు మెమరీలో ట్రాకింగ్ జరుగుతుంది. మీరు స్క్రోల్ చేసినప్పుడు, బ్రౌజర్ మీరు చూస్తున్న భాగాన్ని మాత్రమే కాకుండా, మొత్తం ట్రీ యొక్క స్థానాలను తిరిగి లెక్కిస్తుంది. ఈవెంట్ లిజనర్లు పేరుకుపోతాయి. మెమరీ పెరుగుతుంది. చివరికి మెయిన్ థ్రెడ్ ఎంతగా నిలిచిపోతుందంటే, ఇంటర్ఫేస్ క్లిక్లు, కీస్ట్రోక్లు లేదా స్క్రోల్కు కూడా స్పందించడం ఆగిపోతుంది. సాంకేతికంగా అప్లికేషన్ క్రాష్ కాలేదు, కానీ దాని ముందు కూర్చున్న వినియోగదారుడికి మాత్రం అనుభవం పూర్తిగా దెబ్బతిన్నట్లే.
బ్రౌజర్ ప్రతి ఎలిమెంట్ను ఒకేసారి యాక్టివ్ మెమరీలో ఉంచడానికి ప్రయత్నించడం వల్ల ఇది జరుగుతుంది. మీ UI యొక్క వర్చువల్ వివరణలను (virtual descriptions) సృష్టించడంలో React సమర్థవంతంగా ఉండవచ్చు, కానీ ఆ వివరణలు డాక్యుమెంట్లో నిజమైన నోడ్లుగా మారిన తర్వాత, అవి మామూలు HTML లాగే ఖరీదైనవిగా మారుతాయి. ఫ్రేమ్వర్క్లోనే దీని నుండి తప్పించుకోవడానికి మార్గం లేదు. మీరు లిస్ట్ను DOMకి అందించే విధానంలో ఒక నిర్మాణాత్మక మార్పు (structural change) అవసరం.
వర్చువలైజేషన్ (Virtualization) అంటే నిజంగా ఏమిటి?
వర్చువలైజేషన్ అనేది ఆ నిర్మాణాత్మక మార్పు. మొత్తం అర్రేని రెండర్ చేయమని Reactని అడిగే బదులు, వ్యూపోర్ట్ (viewport) లోపల పట్టే ఐటమ్స్ను మాత్రమే, వాటి పైన మరియు కింద కొంచెం బఫర్తో కలిపి రెండర్ చేస్తారు. వినియోగదారు స్క్రోల్ చేస్తున్నప్పుడు, వ్యూ నుండి బయటకు వెళ్ళే నోడ్లను అప్లికేషన్ తొలగిస్తుంది మరియు అవతలి వైపు నుండి వచ్చే కొత్త నోడ్లను సృష్టిస్తుంది. మొత్తం స్క్రోల్ చేయగల ఎత్తును ఒకే పెద్ద కంటైనర్ ఎలిమెంట్ లేదా జాగ్రత్తగా లెక్కించిన స్పేసర్ ద్వారా కాపాడటం వల్ల, వినియోగదారుడికి ఇది ఇంకా ఒకే నిరంతర జాబితా లాగే అనిపిస్తుంది. కనిపించే ఐటమ్స్ కేవలం డేటాసెట్ అంతటా జారుతున్న ఒక విండో లాంటివి.
దీనిని ప్రొజెక్టర్ గేట్ ద్వారా వెళ్లే ఫిల్మ్స్ట్రిప్ లాగా అనుకోండి. ప్రేక్షకులు మృదువైన కదలికను చూస్తారు, కానీ యంత్రం ప్రస్తుతం స్థానంలో ఉన్న ఫ్రేమ్ను మాత్రమే వెలిగిస్తుంది. మిగిలిన రీల్ ఫీడ్ మరియు టేక్-అప్ స్పూల్స్లో ఉంటుంది, కాంతి మార్గంలో ఉండదు. వర్చువలైజ్డ్ లిస్ట్లు కూడా అదే విధంగా పనిచేస్తాయి. డేటాసెట్ అనేది రీల్, వ్యూపోర్ట్ అనేది గేట్.
ఇది సాంప్రదాయ అర్థంలో లేజీ లోడింగ్ (lazy loading) కాదు. లేజీ లోడింగ్ అనేది వినియోగదారు దాని దగ్గరకు స్క్రోల్ చేసే వరకు డేటాను పొందడాన్ని వాయిదా వేస్తుంది. వర్చువలైజేషన్ అనేది మీ వద్ద ఇప్పటికే డేటా ఉందని భావిస్తుంది, కానీ ఏ భాగాలు నిజమైన DOM ఎలిమెంట్లుగా మారాలి అనే విషయంలో మీరు ఎంపిక చేసుకుంటారు. ఈ రెండు పద్ధతులు కలిసి పనిచేయవచ్చు, కానీ అవి వేర్వేరు సమస్యలను పరిష్కరిస్తాయి.
ఈ తేడా వెంటనే ఎందుకు కనిపిస్తుంది?
ప్రయోజనాలు నాలుగు చోట్ల కనిపిస్తాయి, ఇవన్నీ ఒకే ప్రాథమిక ఉపశమనంపై ఆధారపడి ఉంటాయి: వినియోగదారు చూడలేని వాటి కోసం మీరు ఖర్చు చేయడం ఆపివేస్తారు.
వేగవంతమైన ప్రారంభ లోడ్ సమయాలు. బ్రౌజర్ పేజీని తెరిచినప్పుడు, అది పదిహేను వేల వరుసలకు బదులుగా బహుశా పదిహేను వరుసలను మాత్రమే పెయింట్ చేస్తుంది. మొదటి అర్థవంతమైన పెయింట్ త్వరగా వస్తుంది. జావాస్క్రిప్ట్ ఇంజిన్ నోడ్లను సృష్టించడానికి మరియు వాటిని డాక్యుమెంట్కు అనుసంధానించడానికి తక్కువ సమయం కేటాయించడం వల్ల time-to-interactive తగ్గుతుంది.
తక్కువ మెమరీ వినియోగం. ఒక DOM నోడ్ అనేది ఖరీదైన ఆబ్జెక్ట్. ప్రతి నోడ్ స్టైల్ రూల్స్, లేఅవుట్ మెట్రిక్స్ మరియు ఈవెంట్ బైండింగ్లకు రిఫరెన్స్లను కలిగి ఉంటుంది. యాక్టివ్ నోడ్ కౌంట్ను కొన్ని డజన్లకు తగ్గించడం వల్ల, మెమరీ వినియోగం గణనీయంగా తగ్గుతుంది. తక్కువ సామర్థ్యం ఉన్న పరికరాలలో లేదా సుదీర్ఘ సెషన్లలో, ఇది ట్యాబ్ ఆపరేటింగ్ సిస్టమ్ ద్వారా క్లోజ్ చేయబడకుండా నిరోధించగలదు.
మృదువైన స్క్రోలింగ్ పనితీరు. ట్రీలో తక్కువ నోడ్లు ఉండటం వల్ల, స్క్రోల్ ఈవెంట్ల సమయంలో బ్రౌజర్ లేఅవుట్ మరియు పెయింట్ దశలలో తక్కువ సమయం గడుపుతుంది. కాంపోజిటర్ థ్రెడ్ (compositor thread) దాగి ఉన్న కంటెంట్ యొక్క జ్యామితిని (geometry) నిరంతరం తిరిగి లెక్కించకుండానే కదలికను నిర్వహించగలదు. దీని ఫలితంగా స్క్రోలింగ్ మానిటర్ యొక్క రిఫ్రెష్ రేట్కు దగ్గరగా ఉంటుంది.
స్థిరమైన ఫ్రేమ్ రేట్లు. మెయిన్ థ్రెడ్ ఇక లేఅవుట్ పనిలో మునిగిపోవడం లేదు కాబట్టి, ఇతర కార్యకలాపాలకు అవకాశం ఉంటుంది. యానిమేషన్లు మృదువుగా ఉంటాయి. నెట్వర్క్ స్పందనలను ప్రాసెస్ చేయవచ్చు. రెండర్ పాత్ ఇక అడ్డంకిగా ఉండదు కాబట్టి, కొత్త డేటా వచ్చినప్పుడు UI ఫ్రీజ్ అవ్వదు.
ఇంప్లిమెంటేషన్ను సరిగ్గా చేయడం
React ఎకోసిస్టమ్లో, react-window మరియు మరింత భారీగా ఉండే react-virtualized వంటి లైబ్రరీలు ఈ పద్ధతికి అవసరమైన యంత్రాంగాన్ని అందిస్తాయి. దీని ప్రధాన ఆలోచన స్థిరంగా ఉంటుంది: మీరు ఒక ఐటమ్ రెండరర్ను నిర్వచిస్తారు, మొత్తం ఐటమ్ కౌంట్ను పాస్ చేస్తారు మరియు లైబ్రరీ విండోయింగ్ గణితాన్ని (windowing math) నిర్వహిస్తుంది. కానీ చిన్న చిన్న వివరాలే ప్రజలను తికమకపెడతాయి.
మొదటగా, కంటైనర్కు ఒక నిర్దిష్ట ఎత్తు ఉండాలి. ఒకవేళ లిస్ట్ తనలోని చైల్డ్రెన్కు అనుగుణంగా విస్తరించే పేరెంట్ ఎలిమెంట్ లోపల ఉంటే, వ్యూపోర్ట్ బౌండరీ లేకపోవడం వల్ల ఏ ఐటమ్స్ కనిపిస్తున్నాయో వర్చువలైజేషన్ లెక్కించలేదు. మీరు లిస్ట్ను ఒక ఫిక్స్డ్ హైట్ లేదా తెలిసిన పరిమితులు ఉన్న ఫ్లెక్స్ కంటైనర్లోకి లాక్ చేయాలి.
రెండవది, ఐటమ్ సైజింగ్ చాలా ముఖ్యం. ఫిక్స్డ్-హైట్ రోస్ అత్యంత సులభమైన సందర్భం. లైబ్రరీ రో హైట్ను ఇండెక్స్తో గుణించి, ప్రతి ఎలిమెంట్ను ఎక్కడ ఉంచాలో ఖచ్చితంగా తెలుసుకోగలదు. ఇమేజ్లు ఉన్న చాట్ మెసేజ్లు లేదా కామెంట్ త్రెడ్స్ వంటి వేరియబుల్-హైట్ కంటెంట్ ఉన్నప్పుడు, లైబ్రరీ మౌంట్ అయిన తర్వాత కొలతలను తీసుకుని, వెంటనే సర్దుబాటు చేయాల్సి ఉంటుంది. ఈ కొలత ప్రక్రియ ఆలస్యమైతే స్క్రోల్ జిట్టర్ (scroll jitter) ఏర్పడవచ్చు. మీ డేటా అనుమతిస్తే, ఏకరీతి ఎత్తులను లేదా కనీస ఎత్తులను అమలు చేయండి. లేకపోతే, వేరియబుల్-హైట్ వర్చువలైజర్ను ఉపయోగించి అదనపు సంక్లిష్టతను స్వీకరించండి.
మూడవది, ఓవర్స్కానింగ్ (overscanning) మీకు సహాయపడుతుంది. స్క్రీన్పై సరిగ్గా ఎంత కనిపిస్తుందో అంత మాత్రమే రెండరింగ్ చేస్తే, యూజర్ వేగంగా స్క్రోల్ చేసినప్పుడు ఖాళీ తెల్లటి పట్టీలు కనిపిస్తాయి. చాలా లైబ్రరీలు ఫోల్డ్ పైన మరియు కింద కొన్ని అదనపు ఐటమ్స్ను రెండరింగ్ చేయడానికి అనుమతిస్తాయి. DOM ని మళ్ళీ భారంగా మార్చకుండా, సీమ్స్ను (seams) దాచడానికి సాధారణంగా రెండు లేదా మూడు రోస్ ఓవర్స్కానింగ్ సరిపోతుంది.
నాలుగవది, key ప్రాప్ను నిర్లక్ష్యం చేయకండి. వర్చువలైజ్డ్ లిస్ట్లో, మీరు స్క్రోల్ చేస్తున్నప్పుడు ఐటమ్స్ DOM నోడ్స్ను తిరిగి ఉపయోగిస్తాయి. స్టేబుల్ కీలు (Stable keys) రీకన్సిలియేషన్ సమయంలో React తప్పుగా ఊహించకుండా మరియు రో కాంపోనెంట్లలోని స్టేట్ను నాశనం చేయకుండా నిరోధిస్తాయి. మీ లిస్ట్ రోస్లో ఇన్పుట్లు, టగుల్స్ లేదా ఎక్స్పాండబుల్ సెక్షన్స్ ఉంటే, తప్పు కీలు UI స్టేట్ను పాడు చేస్తాయి. ఇది మీ డేటా లేయర్లో బగ్స్ ఉన్నట్లు అనిపించినప్పటికీ, నిజానికి ఇవి రెండరింగ్ తప్పులు.
ఒక సూక్ష్మమైన చిక్కు బ్రౌజర్ ఫైండ్-ఇన్-పేజీ (find-in-page). దాగి ఉన్న ఐటమ్స్ DOMలో లేకపోవడం వల్ల, బ్రౌజర్ సెర్చ్ బాక్స్ వాటిని గుర్తించదు. మీ యూజర్లు పెద్ద లిస్ట్లో టెక్స్ట్ను కనుగొనడానికి Ctrl+F పై ఆధారపడితే, మీరు డాక్యుమెంట్కు కాకుండా డేటాసెట్పై పనిచేసే కస్టమ్ సెర్చ్ను రూపొందించాల్సి ఉంటుంది. లిస్ట్ సెమాంటిక్స్ (semantics) జాగ్రత్తగా నిర్వహించకపోతే స్క్రీన్ రీడర్స్ కూడా సందర్భాన్ని కోల్పోవచ్చు, కాబట్టి అసిస్టివ్ టెక్నాలజీతో పరీక్షించండి మరియు డైనమిక్ లోడింగ్ కోసం లైవ్ రీజియన్ అనౌన్స్మెంట్లను జోడించడం గురించి ఆలోచించండి.
మీరు దీనిని ఎప్పుడు వదిలేయాలి (Skip చేయాలి)
వర్చువలైజేషన్ ఉచితంగా రాదు. ఇది డిపెండెన్సీ బరువును, కోఆర్డినేట్ మ్యాథ్ను మరియు కన్స్ట్రైంట్ ఓవర్హెడ్ను పెంచుతుంది. మీ లిస్ట్ కేవలం యాభై లేదా వంద ఐటమ్స్తో ముగిసిపోతే, బ్రౌజర్ దాన్ని ఎటువంటి సహాయం లేకుండానే హ్యాండిల్ చేయగలదు. మొత్తం లిస్ట్ను రెండర్ చేసి ముందుకు వెళ్ళండి. మీ లిస్ట్ ఐటమ్స్ వ్యక్తిగతంగా చాలా సంక్లిష్టంగా ఉన్నా కూడా ఇదే వర్తిస్తుంది. వర్చువలైజేషన్ మిమ్మల్ని వేలకొద్దీ నోడ్స్ నుండి కాపాడుతుంది, కానీ ఒకే నోడ్లో భారీ చార్ట్ లేదా వీడియో ఎలిమెంట్ ఉంటే అది మిమ్మల్ని కాపాడలేదు. ముందుగా ఐటమ్ బ్లోట్ను (item bloat) సరిచేయండి.
లిస్ట్ స్క్రోల్ అవ్వనప్పుడు కూడా వర్చువలైజేషన్ను నివారించండి. మీరు నెక్స్ట్ మరియు ప్రివియస్ బటన్లతో పేజినేట్ చేస్తూ, ప్రతి పేజీలో కేవలం ఇరవై ఐటమ్స్ను మాత్రమే చూపిస్తుంటే, అక్కడ విండోయింగ్ (windowing) చేయడానికి ఏమీ లేదు. యూజర్ ఒక పెద్ద వరుస క్రమం (contiguous sequence) ద్వారా స్క్రోల్ చేయాలని ఆశించినప్పుడు మాత్రమే ఈ టెక్నిక్ ఉపయోగపడుతుంది.
అసలైన సారాంశం
వర్చువలైజేషన్ అనేది కేవలం లైబ్రరీ ఎంపిక మాత్రమే కాదు, అది ఒక మైండ్సెట్. DOM అనేది ఒక పరిమిత వనరు అని, అనంతమైన కాన్వాస్ కాదని ఇది మీకు గుర్తు చేస్తుంది. మీరు దీనిని జోడించే ముందు, Chrome DevToolsని ఓపెన్ చేసి, పెర్ఫార్మెన్స్ ప్రొఫైల్ను రికార్డ్ చేయండి మరియు లేఅవుట్ లేదా పెయింట్ టైమ్ నిజంగా సమస్యకు కారణమా అని నిర్ధారించుకోండి. DOM అనేది బాటిల్నెక్ అని తెలిసిన తర్వాత, ఆ పరిమితులకు కట్టుబడి ఉండండి. మీ ఎత్తులను లాక్ చేయండి, కీలను గమనించండి, మితంగా ఓవర్స్కానింగ్ చేయండి మరియు మీ యాక్సెసిబిలిటీని పరీక్షించండి. సరిగ్గా చేస్తే, వర్చువలైజ్డ్ లిస్ట్ ఉపయోగించలేని డేటా గోడను నేటివ్ స్క్రోల్ వ్యూలాగా తేలికగా మారుస్తుంది. బ్రౌజర్ పోరాటం ఆపుతుంది, మీ యూజర్లు వేచి ఉండటం ఆపుతారు మరియు యాప్ మీరు అనుకున్నట్లుగా వేగవంతమైన ఇంటర్ఫేస్లా పనిచేస్తుంది.
