Само преди около половин година решихме да започнем да използваме ES6 в CKEditor 5. Сега целият код използва класове, функции със стрелки, let и const, карти и набори. Тези неща са лесни за възприемане и може да има само няколко съмнения относно това как и кога да ги използвате.

Генераторите и итераторите са различни, защото променят начина, по който мислите за вашия API. Те не са просто още един детайл в изпълнението, тъй като имат смисъл само когато се използват глобално.

Това е повтарящ се въпрос - трябва ли да използваме генератори за това? Не ги ли злоупотребяваме?

Препятствията

Използването на генератори променя начина, по който използвате API - например не можете да повтаряте два пъти един и същ итератор:

const map = new Map( [ [ 1, ‘a’ ], [ 2, ‘b’ ], [ 3, ‘c’ ] ] );
const keys = map.keys();
for ( let key of keys ) {
      console.log( key ); // 1, 2, 3
}
for ( let key of keys ) {
      console.log( key ); // Not executed!
}

Трябва да получите нов итератор всеки път:

const map = new Map( [ [ 1, ‘a’ ], [ 2, ‘b’ ], [ 3, ‘c’ ] ] );
for ( let key of map.keys() ) {
      console.log( key ); // 1, 2, 3
}
for ( let key of map.keys() ) {
      console.log( key ); // 1, 2, 3
}

За разработчици, които са свикнали да кешират свойства, това може да доведе до някои грешки. Особено когато използвате методи, които итерират:

const map = new Map( [ [ 1, ‘a’ ], [ 2, ‘b’ ], [ 3, ‘c’ ] ] );
const keys = map.keys();
 
// In order to count items, the utility must iterate.
if ( utils.count( keys ) < 2 )
     return;
 
for ( let key of keys ) {
      console.log( key ); // Returns nothing!
}

Възможностите

На първо място, ES6 Set и Map API работят по този начин. Ще трябва да се справим с тези недостатъци, независимо дали ни харесва или не. Освен това използването на итератори за връщане на колекции носи някои печалби.

Вие не позволявате на други разработчици да променят вашата колекция

Имахме дискусия дали трябва да клонираме масива, когато го връщаме, за да попречим на разработчиците да правят директни промени. Генераторите решават този проблем: потребителят може да итерира само получените стойности. Ако иска да направи нещо друго, трябва да извика Array.from():

Array.from( selection.getRanges() );

Това ще създаде клонинг на колекцията. Благодарение на това оригиналният масив никога няма да бъде модифициран по погрешка.

Можете да спрете изпълнението на код, когато имате нужда

Имайте предвид, че понякога клонирането на масив не е достатъчно. Може да се наложи да направите дълбоко клониране, за да попречите на потребителя да прави промени. Срещнахме този случай в Selection.getRanges():

*getRanges() {
     for ( let range of this._ranges ) {
        yield range.clone();
    }
}

Това, което ми харесва при използването на генератори е, че например, ако трябва да намерите определен диапазон, тогава няма нужда да клонирате всички диапазони. Когато използвате генератори, ще спрете клонирането веднага щом намерите правилния диапазон:

for ( let range of selection.getRanges() ) {
    if ( range.start.parent == someElement )
        return range;
}

Можете да опростите кода си

Генераторите дават елементи и не е нужно да се интересувате колко сложна е структурата, просто ги взимате и повтаряте. Например в DOM-подобна дървовидна структура имахме колекция от елементи, които може да съдържат фрагменти от документи, смесени с възли. Вместо да изравняваме структурата, успяхме да я итерираме по доста прост начин, делегирайки итерацията на DocumentFragment:

*getNodes() {
     for ( let node of this.nodes ) {
           if ( node instanceof DocumentFragment )
                yield* node;
           else
                yield node;
     }
}

„О, съжалявам, наруших ли концентрацията ви?“

Мисля, че трябва да използваме генератори всеки път, когато връщаме колекции (getChildren(), getAttributes(), getRanges() и т.н.) или в противен случай останете в безопасност в нашата зона на комфорт.

Генераторите са най-голямата промяна в начина, по който мислим за нашия код, откакто беше въведено целево ориентираното програмиране. Но за мен, след първия WTF! момент кодът стана много по-добър и по-чист.