Խնդիրը

Եթե ​​վերջերս կատարել եք որևէ ոչ տրիվիալ ասինխրոն ծրագրավորում, օրինակ, եթե դուք կատարել եք մի քանի լավ backend-ի մշակում NodeJS-ի միջոցով, դուք արագ բախվել եք սիրելի ծրագրավորման պարադիգմը ներխուժող լուրջ խնդրի հետ. ձեր կոդերն արագ դառնում են դժվար ընթեռնելի: և շատ ավելի դժվար է կարգաբերել կոդի կտորների խճճվածքը (սովորաբար փաթաթված անանուն գործառույթների ներսում), որոնք միմյանց հետ կապվում են հատուկ ապշեցուցիչ ձևով: Այլ կերպ ասած, դուք, անկասկած, կա՛մ ստեղծել եք, կա՛մ ստիպված եք եղել աշխատել հետադարձ կապի դժոխքով ծածկագրով.

Promise.all([
  doA().then(aOut =>
    new Promise(resolve => {
      doC(aOut).then(cOut => {
        resolve([aOut, cOut]);
      });
    })),
  doB().then(bOut =>
    new Promise(resolve => {
      doD(bOut);
      resolve(bOut);
    }))
]).then(values => {
  doE(values[0][1], values[0][0], values[1]);
});

Հետադարձ կապի դժոխքները բավականին հեշտ է նկատել, սակայն դրանք լայն տարածում ունեն և հաճախ անխուսափելի են թվում: Թվում է, թե ոչ ոք չի սիրում հետադարձ կապի դժոխքները, ուստի կարելի է վստահորեն ենթադրել, որ ոչ ոք միտումնավոր չի ստեղծի հետադարձ կապի դժոխք, ինչը ենթադրում է, որ դրանք պարզապես հիմքում ընկած պատճառի դրսևորում են: Բայց եթե այդ ենթադրությունը ճշմարիտ է, ապա ո՞րն է լինելու նման պատճառը:

Դե, Դժոխքի հետադարձ կապը ընդհանրապես չի ներծծում հին լավ համաժամանակյա ծածկագիրը, այնպես որ մենք կարող ենք պարզապես փորձել պարզել դրանց պատճառը՝ ավելի խորը նայելով համաժամացման և համաժամացման կոդի հիմնական տարբերությանը:

let aOut = doA();
let bOut = doB();
let cOut = doC(aOut);
doD(bOut);
doE(cOut, aOut, bOut);

Սա համաժամանակյա հակապատկեր է վերոհիշյալ async կոդի համար: Այն տալիս է նույն արդյունքները, սակայն հիմնական տարբերությունը կայանում է դրա կատարման կարգի մեջ (և հետագայում կատարման մեջ).

համաժամացման կոդում doC()-ը կատարվում է doA()-ի և doB()-ի ավարտից հետո, թեև լրացնելու համար պարզապես անհրաժեշտ էր doA() և ոչ doB(): Նմանապես, doD()-ն անհարկի սպասում է, որ doA()-ը և doC()-ը նույնպես ավարտվեն, և doE()-ը սպասում է doD()-ին, մինչդեռ դրա կարիքը չկա:

Համաժամացման կոդում այս անցանկալի «սպասումների» պատճառը պարզ է. համաժամացման կոդը կատարվում է հաջորդաբար: Համաժամեցված կոդի հայտարարությունները հաջորդում են միմյանց, քանի որ դրանք կատարվում են մեկը մյուսի հետևից ճիշտ գրված հաջորդականությամբ: Եթե ​​մենք նկարագրեինք մեր համաժամացման կոդը պարզ անգլերենով, մենք կասեինք «doA() ապա doB() ապա doC() ապա doD() ապա doE()», և եթե մենք լինեինք այս հոսքը ներկայացնելու համար՝ օգտագործելով յուրաքանչյուր հայտարարությունը ներկայացնող տուփ և յուրաքանչյուր «ապա» բառը ներկայացնող սլաք, մենք կստանանք այսպիսի բան.

Քանի որ կոդերի վրա հիմնված մեր ներկայացումը տեքստային է, այն իր էությամբ հագեցած է «պատվերով» հայտարարությունների համար, այսինքն՝ որ հայտարարությունը գրվում է տեքստում, որից հետո, ուստի «սլաքները»: դառնում են անուղղակի և ավելորդ, և մենք դրանք բաց ենք թողնում մեր ծածկագրերից:

Նմանապես, մեր async կոդը անգլերենում կլինի «doA() այնուհետև doC(), միևնույն ժամանակ doB() և ապա doD(), և doA(), doB() և doC() կատարելուց հետո, doE()” որը «արկղերի» և «սլաքների» առումով կթարգմանվի.

Նայելով այս ներկայացմանը, մեր համաժամանակյա կոդի հետ կապված խնդիրն անմիջապես ակնհայտ է դառնում. հայտարարություններին բնորոշ կարգ կա (ուղղակի այն պատճառով, որ դրանք գրված են, և յուրաքանչյուրը պետք է հետևի մյուսին), որն այլևս չկա համաժամանակացված կոդի դեպքում: մեր կատարման կարգը, ուստի մեզ անհրաժեշտ են լրացուցիչ ցուցիչներ (օրինակ՝ Promise.then հետադարձ զանգ կոդի մեջ կամ «ապա»-սլաքները վերևի նկարում)՝ հստակորեն նշելու այդ առանձին կարգը: Այլ կերպ ասած, մեր «ծածկագրի» էական կողմը (որ դա հայտարարությունների կարգավորված հաջորդականություն է) կորցնում է իր իմաստը, և մենք պետք է բացահայտորեն փոխանցենք այդ իմաստը այլ միջոցներով, որոնք, ինչպես տեսնում եք. , հանգեցնում է շատ լրացուցիչ բարդության և դժվարությունների:

Նկատի ունեցեք, որ միայն այն չէ, որ հայտարարությունների հերթականությունը չի համապատասխանում կատարման հրամանին, քանի որ եթե այդպես լիներ, մեր «հայտարարության» տուփերի պարզ խառնումը կլուծեր խնդիրը: Խնդիրն այն է, որ մեր կատարման հոսքն այլևս «հաջորդականություն» չէ, ինչը նշանակում է, որ մենք չենք կարող արդյունավետ կերպով ներկայացնել այն՝ օգտագործելով որևէ «հաջորդականություն», մասնավորապես այն հաջորդականությունը, որով գտնվում են հայտարարությունները։ գրված.

Արդյո՞ք սա նշանակում է, որ խնդիրն այն է, որ async կոդը ի սկզբանե ավելի բարդ է, և այդ պատճառով հետ կանչի դժոխքխնդիրը երբեք չի կարող լուծվել: Ոչ մի կերպ։ Թեև async կոդը ի սկզբանե ավելի բարդ է, դա չի նշանակում, որ մենք երբեք չենք կարող լուծել հետ կանչի դժոխք խնդիրը: Իրականում, բազմաթիվ լուծումներ արդեն առաջարկվել և իրականացվել են տարբեր լեզուներով և շրջանակներով, ուստի արժե նայել ամենահայտնիներին՝ վերլուծելու համար, թե արդյոք դրանք իսկապես լուծում են խնդիրը:

Խոստումներ

Խոստումորտեղ առաջին լուծումը ներկայացվեց Javascript համայնքին որպես վերոհիշյալ խնդրի լուծում: Դրանք ի սկզբանե առաջարկվում էին որպես որոշ փաթեթների մաս և այնքան էին գնահատվում համայնքի կողմից, որ ընդունվեց որպես հենց ծրագրավորման լեզվի մաս: Ըստ էության, համաժամանակյա կոդերը նման էին հետևյալին.

doA((err, aOut) => {
  // ...
}

Այս կառուցվածքը հանգեցրեց սարսափելի խառնաշփոթ կոդերի, քանի որ ուղղակի համաժամացման գործառույթը կանչող հայտարարությունը կներառի հետադարձ կապի ամբողջ շղթան, այսինքն՝ դուք չեք կարող առանձնացնել գործառույթի կանչերը՝ առանց ամբողջ հոսքը կարդալու: Բացի այդ, կան բազմաթիվ համաժամանակյա հոսքեր, որոնք դուք պարզապես չեք կարող նկարագրել այս կառուցվածքով: Օրինակ, կարող եք փորձել նորից գրել մեր սկզբնական համաժամանակյա կոդը հետ կանչի փաստարկների առումով և տեսնել, թե ինչպես է այն աշխատում:

Այնուամենայնիվ, Խոստումները չեն կարողանում իրականում լուծել խնդիրը, քանի որ նույնիսկ իրականում չեն լուծվում այն: Մեր սկզբնական օրինակը հետ կանչի դժոխքի գրվել է ոչ թե հետ կանչի փաստարկների, այլ իրականում խոստումների առումով: Համեմատելով մեր գրաֆիկների հետ՝ «Խոստումները» հիմնականում շատ ավելի կոկիկ ձև են՝ ներկայացնելու «սլաքները», այնպես որ, բնականաբար, դրանք չեն կարող որևէ բան անել, որպեսզի օգնի բարդ խճճվածությանը, որը մենք ունենք հենց գրաֆիկի վրա:

Async/Await

async/await այս խնդիրը լուծելու նորագույն փորձն է (գոնե Javascript-ի համար): Այն աշխատում է բավականին պարզ. await-ը պարզապես ստիպում է ֆունկցիայի մարմնի մնացած մասը «սպասել»ավարտելու հայտարարությունը, այն նկատառումով, որ այժմ ամբողջ ֆունկցիան պետք է նշվի: async, ինչը նշանակում է, որ սա ասինխրոն ֆունկցիա է:

Գործնականում սա մեզ տալիս է չափազանց նման հոսքի գրաֆիկներ, ինչ լրիվ համաժամացման կոդի դեպքում, քանի որ ճիշտ համաժամացման կոդի նման await-ին հաջորդող հայտարարությունները պետք է «սպասեն» դրա կատարմանը: Սա նույն դեպքն էր, ինչ մենք ունեինք մեր async կոդի և դրա համաժամացման գործընկերոջ միջև հիմնական տարբերակման հետ: Միակ տարբերությունն այն է, որ ամբողջ համատեքստն այժմ դառնում է համաժամանակյա, ինչը թույլ է տալիս հիմքում ընկած շարժիչին միաժամանակ կատարել այլ գործեր:

Այլ կերպ ասած, async/await-ը նույնպես նախատեսված չէ խնդիրը լուծելու համար, այն պարզապես գործիք է խնդիրը մեղմելու համար, երբ կատարման հոսքն ինքնին իրականում հաջորդականություն է: Այսպիսով, թեև դա օգնում է ավելի պարզ իրավիճակներում, կրկին օգտակար չի լինի ոչ մի տեղ, որ իրական համաժամանակյա հոսքը պետք է մշակվի: Դա ինքներդ տեսնելու համար փորձեք նորից գրել մեր համաժամեցված կոդի հատվածը՝ օգտագործելով միայն async/await հայտարարությունները և տեսեք, թե ինչպես է այն դուրս գալիս (Խմբագրել. ինչն իրականում հնարավոր է՝ շնորհիվ jmull-ի՝ դրա համար բավականին կոկիկ լուծման համար) .

Խենթ գաղափարը

Լավ, քանի որ վերոհիշյալ լուծումներից և ոչ մեկը չի ուղղված խնդրի առանցքը async կոդի հետ, եկեք հասնենք այն խելահեղ գաղափարին, որը կարող է լուծել այն: Պարզապես կրկնելու համար, մեր խնդիրն այն էր, որ համաժամանակյա հոսքի գրաֆիկը ինքնին խճճված է (որը, բնականաբար, դրսևորվում է դժոխքի հետադարձ կապի խճճվածության, խոստանում, ապա խճճվածության տեսքով, և այլն):

Ուշադիր նայեք այս խնդրահարույց գրաֆիկին և կնկատեք, որ «սլաք» կապերի խճճվածությունը այս գրաֆիկի բնածին խնդիր չէ, այլ իրականում մեր ընտրության ներկայացումից առաջացող երևույթ: Այլ կերպ ասած, այնպես չէ, որ գրաֆիկը, որը մենք փորձում ենք ներկայացնել, ի սկզբանե գերբարդ է, պարզապես այն այնպես, որ մենք պնդում ենք այն ներկայացնելը, այն բարդացնում է: Մենք կարող ենք պարզապես դուրս հանել « տուփի »ների հաջորդական ձևով գծելու պահանջը, և մենք կարող ենք այս գրաֆիկը վերադասավորել այսպես.

Պարզ, այնպես չէ՞: :)

Դե, այս կետով դուք կարող եք զարմանալ, որ OK-ը, որը կարծես մեր ասինխրոն կատարման հոսքի ավելի պարզ ներկայացում է, այնուամենայնիվ, դա մեր ներկայացման «հաջորդականությունը» պատուհանից դուրս նետելու արդյունք է: ինչը գործնականում հնարավոր չէ անել, քանի որ, ի վերջո, ցանկացած կոդ հայտարարությունների հաջորդականություն է: Եվ դուք ճիշտ կլինեք։

Եվ ահա թե ինչու դա խելահեղ գաղափար է. իսկ եթե մենք չկոդավորեինք հայտարարությունների հաջորդականության տեսքով, այլ իրականում այսպիսի գրաֆիկի տեսքով: այսինքն՝ ի՞նչ, եթե մենք փոխարինենք հաջորդականկոդերը գրաֆիկականով բնածին ասինքրոն կոդերի համար:

Դե, ես ինքս ինձ նման հարց տվեցի մոտ մեկ տարի առաջ, և քանի որ ասինխրոն ծրագրավորման բնածին խնդիրները, համենայն դեպս, ինչպես մենք դա անում ենք ներկայումս, անընդհատ խանգարում էին ինձ և դանդաղեցնում ինձ ամեն օր, ես սկսեցի կամաց-կամաց մշակել նախատիպը: դրա համար ուշ ժամերին, գուցե ամեն շաբաթ մեկ կամ երկու գիշեր: Մեկ տարվա ընթացքում, որոշ ընկերների օգնությամբ և խրախուսմամբ, այդ նախատիպը վերածվեց CONNECT-ի՝ հարթակի, որը կառուցվել է հենց վերոհիշյալ խնդիրը լուծելու համար, և ըստ էության ունի հետևյալ տեսքը.

Իհարկե, CONNECT-ը կառուցված է ոչ թե որպես համընդհանուր նշանակության ասինխրոն կոդավորման հարթակ, այլ որպես ուղղություն, որը նպատակաուղղված է հատուկ backend-ի մշակմանը և նույնիսկ ավելի կոնկրետ տրամաբանական միկրո ծառայությունները հետին մասում: Ինչու backend? Քանի որ առջևի ասինխրոն կոդերն իրենց ասինխրոնիկության առումով շատ ավելի թեթև են, ինչպես նաև ներառում են մատուցման շատ տրամաբանություն, ինչը խնդիրն ըստ էության տարբեր է դարձնում: Ինչու՞ տրամաբանական: որովհետև նորից, հաշվողական հետին ծածկագիրը սովորաբար այնքան էլ ասինխրոն չէ, և որպես այդպիսին վերաբերվելը իրականում ձեզ ավելի դանդաղեցնելու է: Իսկ ինչո՞ւ միկրոծառայություններ: Դե, հիմնականում, քանի որ դրանք հետին պլանի զարգացման ապագան են:

Բացի այդ, դա անելով մենք հասկացանք, որ backend-ի տրամաբանությունը զուտ ասինխրոն չէ բոլոր մակարդակներում, և ավելի հաճախ այն կարծես համաժամանակյա բլոկներ լինեն, որոնք միմյանց հետ կապված են ասինխրոն ձևով: Բարեբախտաբար, մենք հեշտությամբ կարողացանք դա ներդնել CONNECT, քանի որ այն արդեն կառուցված էր NodeJS/ExpressJS-ի վերևում և անխափան կերպով աջակցում էր Javascript արտահայտությունները գրաֆիկի մեջ: Մենք պարզապես թույլ տվեցինք, որ յուրաքանչյուր հանգույց ինքնուրույն դառնա ամբողջական սինխրոն բլոկ:

Մտահոգություններ, կողմ և դեմ

Մտահոգություն թիվ 1. Վիզուալ ծրագրավորումը ծրագրավորում չէ

Ես գիտակցում եմ, որ ավանդաբար ծրագրավորողները (ներառյալ ես) դեմ են «տեսողական» ծրագրավորմանը, քանի որ դա գրեթե միշտ եղել է մի բան, որը ուղղված է եղել «ավելի քիչ բանիմաց» մարդկանց, և ընդհանրապես միշտ եղել է: « fine-control » « պարզությամբ » առևտրի արդյունք էր, փոխզիջում, որը, մեղմ ասած, առնվազն զայրացնում է ցանկացած բավական լուրջ ծրագրավորողի:

Այնուամենայնիվ, դա այդպես չէ CONNECT-ի դեպքում (կամ ընդհանրապես գրաֆիկական վրա հիմնված կոդավորման մոտեցման համար, որը համաժամանակյա հոսքերի համար), քանի որ իրականում այն ​​առաջարկում է ավելի նուրբ հսկողություն՝ համեմատած հետադարձ կապի փաստարկների կամ async/await հայտարարությունների հետ և առաջարկում է առնվազն նույն քանակությամբ վերահսկողություն: ինչպես անում են Promises. Իրականում, եթե ինչ-որ բան, սուպեր լուծումները մեզ հնարավորություն են տալիս շատ ավելին անել մեր զարգացած ասինխրոն հոսքերի հետ: Սա ոչ թե վերահսկողության զիջում է, այլ պարզապես վերացնում է մի սահմանափակում, որը հիմնականում հետ է պահում մեզ, թեև այդ սահմանափակումը կարող է լինել ցանկացած կոդի հատկություն, որը մենք արել ենք երկար ժամանակ, և, հետևաբար, մենք իսկապես սովոր ենք դրան:

Մտահոգություն #2. Նման գործիքի կիրառումը սահմանափակ կլինի

Դե, քանի որ այս մոտեցումը չի հեռացնում վերահսկողությունը ծրագրավորողներից և պարզապես առաջարկում է ավելի օպտիմալ ներկայացում, այնպես չէ, որ այն, ինչ դուք կարող եք կառուցել նման գործիքով (օրինակ՝ ՄԻԱՑՈՒՄ), ավելի սահմանափակ են, այլ իրականում դուք շատ ավելի հեշտ կլիներ կառուցել շատ ավելի բարդ համաժամանակյա տրամաբանություն:

Դա իրականում ապահովելու համար մենք նույնիսկ կառուցեցինք CONNECT-ի Հարթակը որպես ծառայություն՝ օգտագործելով հենց CONNECT-ը: Դա ոչ միայն մեզ ոչ մի կերպ չխանգարեց, այլև մենք կարողացանք դա իրականացնել զարմանալիորեն արագ ժամանակահատվածում (4 օրից մինչև մեկ շաբաթ, այն պահից, երբ մենք գրանցեցինք տիրույթը և որոշեցինք ներգրավված տարբեր միկրոծառայությունների անունները: մինչև այն պատրաստ լինի գործարկել CONNECT օրինակները ցանկացած գրանցված օգտատիրոջ համար, քնեցնել նրանց րոպեներ անգործությունից հետո և արթնացնել նրանց՝ ի պատասխան հարցումների):

Իհարկե, հատկանշական է, որ քանի որ սա ասինխրոն ծրագրավորման մոտեցում է: Կան ծրագրավորման այլ ենթատեքստեր, որոնք հաստատ ընդհանրապես չեն շահի նման մոտեցումից, ճիշտ այնպես, ինչպես նրանք չեն շահի Promise s կամ async/await հայտարարություններից:

Pro #1: Արդյունավետություն

Քանի որ այս մոտեցումը նախատեսված է հոսքի ներկայացումը շատ ավելի արդյունավետ և անխոչընդոտ դարձնելու համար, այն, բնականաբար, պետք է հանգեցնի նշված ներկայացման ընթերցման/գրելու ավելի ցածր ճանաչողական բեռի, ինչը կհանգեցնի զարգացման շատ ավելի արագ ժամանակի (և հետևաբար զարգացման շատ ավելի ցածր ծախսերի): . Այլ կերպ ասած, գրել կամ կարդալ այս գրաֆիկը

ակնհայտորեն շատ ավելի հեշտ կլիներ և, հետևաբար, շատ ավելի քիչ ժամանակատար, քան այս մեկը.

Pro #2: Պահպանելիություն

Սա առաջինի բնական արդյունքն է։ Քանի որ կոդի ընթացքին կարդալն ու հետևելը շատ ավելի հեշտ է դառնում, այն նաև շատ ավելի հեշտ է դառնում դրա վրիպազերծումը կամ փոփոխություններ կատարելը, ինչը համաժամեցված ծրագրավորման մեր ներկայիս մոտեցումների հիմնական խոչընդոտներից մեկն է:

Իրականում, գործընթացն այնքան անխափան է դառնում, որ մենք հասկացանք, որ իրականում կարող ենք հեշտությամբ արձանագրել գրաֆիկների կատարումը CONNECT-ում և վերարտադրել դրանք իրական ժամանակում՝ ոչ միայն մեծապես օգնելով փորձարկման և վրիպազերծման, այլ նաև կատարողականի ստուգմանը.

Pro #3: Կատարում

Քանի որ ասինխրոն ծրագրավորման այս մոտեցումը իրականում թույլ է տալիս ավելի լավ վերահսկել ձեր ասինխրոն հոսքը, այն օգուտ է բերում առաջադրանքների շատ ավելի լավ կազմակերպում, որոնք կարող են իրականացվել զուգահեռ՝ նվազեցնելու արձագանքման ժամանակը: Թեև դուք կարող եք դա անել նաև ավանդական մոտեցումներով, քանի որ ցանկացած ոչ տրիվիալ ասինխրոն հոսքի կառավարումը կբարձրացնի զարգացման և պահպանման ծախսերը, շատ դեպքերում դուք կվտանգի որոշ կատարողականություն՝ այդ ծախսերը ցածր պահելու համար: Այնուամենայնիվ, գրաֆիկի վրա հիմնված այս մոտեցումը ձեզ հնարավորություն է տալիս խորանալ նման օպտիմալացումների մեջ՝ չվախենալով զարգացման/սպասարկման ծախսերի ավելացումից:

Դեմ # 1. Async հոսքերը էապես տարբեր են

Քանի որ CONNECT-ի հետ առաջին նախագծերից մեկը Պլատֆորմը որպես ծառայություն էր, մենք արագ բախվեցինք դրան. այժմ, երբ async հոսքերը, որոնք մենք սովորաբար անում էինք, դարձել են շատ հեշտ կառավարելը, մենք արագորեն ստեղծեցինք շատ ավելի բարդ: հոսքեր և գրաֆիկներ (որոնց հակառակ դեպքում մենք հաստատ կխուսափեինք, քանի որ դրանց տեքստի վրա հիմնված ներկայացումները չափազանց դժվար կլիներ մշակել), որոնք, համապատասխանաբար, մեզ համար դժվար էին հասկանալ և աշխատել դրանց հետ:

Սա նաև հայտնվեց մեր հավաքած բավականին վաղ օգտատերերի հետադարձ կապերի ժամանակ. մարդկանց մեծամասնությունը սովոր է համաժամանակ մտածել իրենց ծածկագրերի և ծառայությունների մասին, և լավ պատճառով. համաժամանակյա համատեքստում դուք կարող եք հստակ իմանալ, թե կոնկրետ որ հայտարարությունն է կատարվում յուրաքանչյուրում։ քայլ, հսկողություն, որը դուք բնականաբար կորցնում եք՝ անցնելով համաժամանակյա երթուղին: Եվ չնայած այս տեսակի մարտահրավերները սովորաբար թաքնված են հետադարձ կապի դժոխքների գլխացավի հետևում, երբ մենք լուծեցինք այդ գլխացավերը, դրանք ի հայտ եկան, և մենք արագ հասկացանք, որ ընդհանուր առմամբ ձեզ հարկավոր է այլ մտավոր մոտեցում ձեր ավելի բարդ ասինգրաֆիկներին, քան այն, ինչ դուք կկատարեիք ձեր հաջորդական գրաֆիկներին: ծածկագրերը։

Այնուամենայնիվ, ըստ մեր, անկասկած, բավականին սահմանափակ թեստերի, մարդկանց համար այդքան ժամանակ չի պահանջվում նոր պահանջվող ճանաչողական մոտեցումը որդեգրելու համար, թեև այստեղ, անկասկած, ուսուցման կոր կա:

Դեմ թիվ 2: Գործիքավորում

CONNECT-ի համար մենք փորձեցինք վերօգտագործել մեզ հասանելի արդեն իսկ հասանելի գործիքներից և տեխնոլոգիաներից և պարզապես ավելացնել գրաֆիկի վրա հիմնված ներկայացումը, որը մենք նախատեսել էինք: Այն հիմնված է NodeJS-ի վրա, ինչը նշանակում է, որ բոլոր NPM փաթեթները հասանելի են դրա համար (որն այնտեղ հասանելի փաթեթների ամենամեծ պահեստներից մեկն է): Մենք նույնիսկ ստեղծել ենք մարդու համար հարմար JSON-ի վրա հիմնված ձևաչափ տրամաբանական գրաֆիկների համար, որպեսզի կարողանաք հեշտությամբ կառավարել դրանք (օրինակ՝ օգտագործելով git):

Չնայած այս ամենին, մեր փորձնական օգտատերերից մեկից բավականին վաղ արձագանքն այն էր, որ նա խնդրում էր հեռացնել գրաֆիկի որոշ տվյալներ, որպեսզի կարողանա կարդալ git-diffs-ը ավելի հեշտ ձևով: Այս դեպքում, թեև մարդու համար հարմար ձևաչափը շատ է օգնում, այնուամենայնիվ JSON-ֆայլից գծապատկեր կարդալը նույնքան արդյունավետ է, որքան ասինխրոն հոսքը հաջորդական ձևաչափի մեջ դնելը, դա անխուսափելիորեն սովորականից ավելի դժվար կլինի: Թեև մենք պլանավորում ենք ավելացնել git-ի վրա կենտրոնացած շատ գեղեցիկ հատկություններ (ներառյալ բավականին տարբերություններ) CONNECT հոսքի գծապատկերների համար, փաստ է, որ դուք կկորցնեք զարգացման գործիքների հասանելիությունը, որոնք տարիներ շարունակ մշակվել են, ենթադրելով, որ դրանք կօգնեն տեքստի վրա հիմնված կոդեր, և դրանցից մի քանիսը պետք է զրոյից մշակվեն գրաֆիկի վրա հիմնված կոդերի համար:

Եզրակացություն

Async ծրագրավորումը ախտահարված է կոդերի խճճվածությամբ և հետադարձ կապով, պարզապես այն պատճառով, որ async լինելը նշանակում է ունենալ ոչ գծային ոչ հաջորդական կատարողական հոսք, որը հակասում է հաջորդական բնույթին: տեքստի վրա հիմնված կոդեր: Առաջարկվող լուծումն այստեղ գծապատկերի վրա հիմնված կոդերն է, որոնցում դուք հստակ և օպտիմալ կերպով ուրվագծում եք կատարման հոսքը, որը կարող է լինել նաև համաժամանակյա կոդերի բլոկների միջև:

Ի՞նչ եք կարծում, այս արմատական ​​մոտեցումը կաշխատի: Դե շահարկումների կարիք չկա, քանի որ մենք ստեղծել ենք հարթակ, որը պարզապես հնարավորություն է տալիս փորձարկել այն ինքներդ: Փորձեք այն և կիսվեք ձեր մտքերով և կարծիքներով: