Ես պարզապես ջնջեցի երեկ գրածս հարյուրավոր տող կոդ և դրանք փոխարինեցի նոր կոդով 32 տողով: Սա TheOpenPresenter- ի գործառույթի համար էր, որն օգտագործվում էր ցույց տալու համար, թե արդյոք աուդիո նվագարկվում է:
Շատ հաճախ ես կաշխատեի մի ֆունկցիոնալության վրա, որն իրագործումը բավականին պարզ է թվում: Այս դեպքում ես պարզապես պետք է ցույց տայի այս պատկերակը, երբ աուդիո նվագարկվում է:
Բավականին պարզ: Սրանցից յուրաքանչյուրը մի տեսարան է, որը պարունակում է բազմաթիվ պլագիններ: Յուրաքանչյուր փլագին ունի իր սեփական հատկությունը, ինչպիսին է isPlaying
: Մենք կարող ենք միավորել արժեքները պլագինների միջև, և եթե դրոշը ճիշտ է, մենք կարող ենք ցույց տալ պատկերակը:
Հիմնական խնդիրն այն է, թե ինչպես մուտք գործել այս տվյալները: Տեսեք, մենք կարող էինք ուղղակիորեն մուտք գործել տվյալներ: Բայց յուրաքանչյուր փլագին կարող է ունենալ իր սխեման: Թեև որոշ պլագիններ կարող են ունենալ պարզ isPlaying հատկություն, որոշ այլ հավելվածներ կարող են ավելի բարդ բանի կարիք ունենալ՝ ներկայացնելու դրա խաղային կարգավիճակը:
Պարզ, ինչու՞ չթույլատրել հավելվածին գրանցել հետադարձ զանգ/գործառույթ, որը վերադարձնում է վիճակը:
Սա նույն օրինաչափությունն է, որը TheOpenPresenter-ն օգտագործում է իր շատ հավելումների համար: Եվ մինչ մենք դրանում ենք, մենք կարող ենք այն վերացարկել SceneState օբյեկտի մեջ: Այսպիսով, եթե մենք երբևէ որևէ այլ պետության կարիք ունենանք, մենք կարող ենք այն ավելացնել այստեղ: Ահա թե ինչպես այն կարող է նման լինել plugin-ի համար.
// The pattern we use for plugins serverPluginApi.onPluginDataCreated(pluginName, onPluginDataCreated); serverPluginApi.onPluginDataLoaded(pluginName, onPluginDataLoaded); serverPluginApi.registerRemoteViewWebComponent( pluginName, remoteWebComponentTag, ); // Example of how the new API might look like serverPluginApi.registerSceneState( pluginName, (_, rendererData) => { return { audioIsPlaying: !!rendererData.find((x) => x.isPlaying), } }, );
Ուշադրություն դարձրեք, որ վերը նշված կոդը մշակվում է սերվերում: Դա պայմանավորված է նրանով, որ TheOpenPresenter-ը բաղկացած է 3 առանձին բաղադրիչներից.
Հեռակառավարման վահանակ - որտեղ ցուցադրվում է այս աուդիո ցուցումը
The Renderer - նվագարկում է աուդիո
Սերվեր - միացնում է երկուսը
Իդեալում, մենք պետք է դա կարգավորենք ճակատային մասում (հեռավոր), որպեսզի լրացուցիչ բեռ չավելացնենք սերվերին: Այնուամենայնիվ, այս գործառույթը գրանցելը կարող է խառնաշփոթ լինել: Մեր ճակատային մասը օգտագործում է վեբ բաղադրիչներով բեռնված միկրո-առանցքային ճարտարապետություն:
Ներքևում գտնվող կարմիր տարածքը React շերտ է: Կանաչ տարածքը բեռնվում է վեբ բաղադրիչների միջոցով և կառավարվում է յուրաքանչյուր հավելվածի կողմից:
Ուշադրություն դարձրեք, որ աուդիո պատկերակը գտնվում է կեղևի ձախ կողմում: Ինչպե՞ս ենք ապահովում մեզ անհրաժեշտ գործառույթը shell-ին: Մենք կարող ենք ներառել JS ֆունկցիա վեբ բաղադրիչի փաթեթում, բայց դա երկարաժամկետ հեռանկարում խառնաշփոթ է թվում:
Սերվերում սրա հետ վարվելը կարծես դա անելու ճիշտ միջոց է:
Այդ որոշմամբ՝ ժամանակն է իրականացման: Կան մի քանի անելիքներ.
Ես ձեզ չեմ ձանձրացնի մանրամասներով, այնպես որ ահա ակնարկ: API-ն այնքան էլ պարզ չէր, քանի որ մեր տվյալները կարող են բավականին շփոթեցնող լինել: Մի խոսքով, տեսարանը կարող է ունենալ բազմաթիվ պլագիններ: Եվ կարող են լինել մի քանի մատուցողներ, որոնցից յուրաքանչյուրը յուրովի է դիտում տեսարանը: Այսպիսով, plugin-ը կարող է ունենալ բազմաթիվ մատուցողներ, որոնք ցույց են տալիս այն տարբեր ձևերով: Բայց մի փոքր տվյալների մանիպուլյացիայով խնդիրը լուծվեց:
UI-ի սպառում և թարմացում
Արժեքը սպառելը պարզ էր: Ես մտածեցի օգտագործել Yjs-ի իրազեկման արձանագրությունը տվյալների տրամադրման համար, քանի որ դրանք իրական ժամանակում են, և շրջանակն արդեն տեղադրված է: Այսպես է պահվում պետությունը։ Այնուամենայնիվ, սերվերից այս տվյալները ներառելը իր խնդիրն է: Այսպիսով, ես որոշեցի փոխարենը օգտագործել GraphQL-ը, այն արձանագրությունը, որը մենք օգտագործում ենք հարթակի մնացած ամեն ինչի համար:
Այսպիսով, մեզ անհրաժեշտ է միայն զանգահարել վերջնակետը, լսել այն GraphQL-ի բաժանորդագրության միջոցով և անհրաժեշտության դեպքում ցույց տալ պատկերակը: Կատարված է:
Այս տվյալները տրամադրելով ճակատին
Բարեբախտաբար, մենք օգտագործում ենք Postgraphile-ը , ինչը բավականին պարզ է դարձնում GraphQL սխեմայի ընդլայնումը: Մենք կարող ենք նաև այն դարձնել բաժանորդագրություն՝ պարզապես ավելացնելով @pgSubscription
GraphQL սխեմային: Այնուհետև այն կդիտի թեմա և կթարմացնի արժեքը, երբ մենք զանգահարենք pg_notify
այդ թեմայով: Օրինակ՝
await pgPool.query( `select pg_notify('graphql:sceneState:${id}','{}');`, [], );
Տվյալների մանիպուլյացիան նյարդայնացնող էր, բայց մի փոքր համբերություն, և դա արված է:
Փազլի վերջին մասը կանչում է pg_notify
, երբ դա մեզ անհրաժեշտ է:
Դրա համար մենք կարող ենք ունկնդիր ավելացնել վիճակին (Yjs) և զանգահարել ծանուցում, երբ ինչ-որ բան փոխվի.
state.observeDeep(async () => { // Call pg_notify here });
Միակ բանը, որ մնում է անել, կատարողականի բարելավումն է: Հենց հիմա ֆունկցիան կանչվում է յուրաքանչյուր փոքր փոփոխության համար, այն նաև թարմացվում է ճակատային մասում: Մենք կարող ենք հաշվարկել ստացված վիճակը և համեմատել, արդյոք ինչ-որ բան փոխվում է, նախքան թարմացումը մղելը:
Այժմ այս լուծումը, անշուշտ, աշխատում է: Բայց ես ատում էի, որ մենք լսում էինք յուրաքանչյուր փոփոխություն: Դա ավելորդ է, և ես վստահ չեմ, թե ինչպես է ներկայացումը մասշտաբի: Ավելի լավ լուծում կա՞:
Այսպիսով, ես մի վայրկյան հետ քաշվեցի և մի միտք ծագեց. Ի՞նչ կասեք, որ գնանք հիմունքներին և օգտագործենք Yjs-ի տվյալները:
Խնդիրն այն էր, որ յուրաքանչյուր փլագին կարող է օգտագործել տարբեր եղանակներ՝ խաղալու կարգավիճակը նշելու համար: Այսպիսով, մեզ անհրաժեշտ էր միջոց՝ իմանալու, թե ինչպես ինքնուրույն հաշվարկել ստացված վիճակը: Բայց ոչ թե թույլ տալ, որ օգտատերը փոխանցի գործառույթը, ինչո՞ւ չպահագրել սեփականություն, որը նրանք կարող են օգտագործել դա նշելու համար:
Վիճակը հաշվարկելու համար գործառույթ փոխանցելու փոխարեն, յուրաքանչյուր փլագին կարող է սահմանել վերապահված վիճակը անմիջապես իրենց առկա տվյալների կողքին՝ __audioIsPlaying
նման հատկություններով: Նրանք կարող էին ուղղակիորեն օգտագործել այս արժեքը, կամ նրանք կարող էին այն համաժամանակացնել իրենց գոյություն ունեցող հատկությունների հետ, ինչպիսիք են.
const onRendererDataLoaded = ( rendererData, ) => { watchYjs( // Watch the isPlaying property (x) => x.isPlaying, () => { // And if it changes, sync the __audioIsPlaying property rendererData.set("__audioIsPlaying", rendererData.get("isPlaying")); }, ); };
Նոր մեթոդը փայլուն է. Ոչ մի լրացուցիչ լսող, ոչ մի լրացուցիչ API, պարզապես վերապահված պարզ հատկություն:
Արժեքը. Դե ես արդեն գրել եմ առաջին իրականացման 95%-ը 🫣
«Այնքան ամոթ կլինի ջնջել սա, երբ ես այդքան երկար աշխատել եմ դրա վրա: Մնացած ամեն ինչ կատարյալ է, բացի այս մեկ բանից»: -Իմ միտքը
Սա իմ առաջին անգամը չէ։ Ոչ երկրորդ, ոչ երրորդ: Այս անգամ ընդամենը մի քանի ժամ աշխատանք էր։ Որքան ժամանակ է պահանջվում դրա իրականացման համար, այնքան դժվար է այն բաց թողնելը: Բայց եթե մենք չպետք է կցվենք սերվերներին, մենք նույնպես չպետք է կցվենք մեր գրած կոդին:
Ակնհայտ է, որ երկրորդ իրականացումն ավելի լավն է։ Այն ավելի արագ է, ավելի քիչ շարժվող մասեր, ավելի քիչ API մակերես և ավելի քիչ կոդ, որը պետք է պահպանվի: Առաջին իրականացումն ավելացրել է 289 նոր տող, մինչդեռ երկրորդ իրականացումն ավելացրել է ընդամենը 32 նոր տող:
Ի՞նչ դաս պետք է սովորել այդ դեպքում:
Դե, գուցե նախ գտնեք ամենապարզ լուծումը: Բայց երբեմն միայն դրա մասին մտածելով չենք հասնում լավագույն լուծմանը: Եթե դա այդպես է, մի սիրեք ձեր կոդը և մի վախեցեք այն դեն նետել : Եվ միգուցե բլոգային գրառում գրեք, որպեսզի դրանից ինչ-որ բան ստանաք:
Եթե այսքան հեռու եք կարդացել, գուցե ցանկանաք փորձել TheOpenPresenter-ը : Սա բաց կոդով ներկայացման համակարգ է, որը թույլ է տալիս հեռակա կարգով կառավարել ձեր էկրաններից որևէ մեկը:
Ցույց տալ սլայդերի ցուցադրումներ, նվագարկել տեսանյութեր, օգտագործել որպես վահանակ և շատ ավելին: Ծրագիրը դեռ շատ վաղ է մշակվում, ինչպես կարող եք ասել այս գրառումից, բայց այն բավականաչափ կայուն է կանոնավոր օգտագործման համար: Ես անձամբ օգտագործում եմ այն ամեն շաբաթ իմ հանդիպումների համար:
Ցանկացած հարց, հարցրեք: Կամ ազատ զգալ զեկուցել Github ռեպո-ի խնդիրների մասին: