Контекст операции
Контекстом операции называется специальный объект, который содержит ряд методов и свойств для работы с исполняемой итеративной функцией.
/**
* @typedef ctx
* @typedef $$CollectionCtx
*/
- true
- false
- $
- info
- result
- length
- i
- jump
- id
- reset
- break
- childResult
- yield
- next
- value
- child
- wait
- race
- sleep
- thread
- onError
/**
* @type {Object}
* @typedef TRUE
* @readonly
*/
ctx.true
— это ссылка на объект, который всегда означает положительное значение. Если фильтр вернёт данное значение,
то конкретный элемент всегда будет включаться в выборку, т.е. вне зависимости от параметра inverseFilter.
$C([1, 2, 3]).get(() => true) // [1, 2, 3]
$C([1, 2, 3]).get(() => true, {inverseFilter: true}) // []
$C([1, 2, 3]).get((el, i, data, o) => o.true, {inverseFilter: true}) // [1, 2, 3]
/**
* @type {Object}
* @typedef FALSE
* @readonly
*/
ctx.false
— это ссылка на объект, который всегда означает отрицательное значение. Если фильтр вернёт данное значение,
то конкретный элемент всегда будет исключаться из выборки, т.е. вне зависимости от параметра inverseFilter.
$C([1, 2, 3]).get(() => false) // []
$C([1, 2, 3]).get(() => false, {inverseFilter: true}) // [1, 2, 3]
$C([1, 2, 3]).get((el, i, data, o) => o.false, {inverseFilter: true}) // []
/**
* @type {Object}
*/
ctx.$
— это ссылка на объект, который предназначен для мемоизации различных параметров. Все функции обработчики
имеют доступ к этому объекту в рамках конкретной операции.
$C([1, 2, 3, 4])
.filter((el, key, data, o) => !o.$.ignore)
.map((el, key, data, o) => {
o.$.ignore = true;
return el * 2;
}) // [2]
/**
* @type {{
* filters: Array<Function>,
* mult: (boolean|number),
* startIndex: (boolean|number),
* endIndex: (boolean|number),
* from: (boolean|number),
* count: (boolean|number),
* live: boolean,
* reverse: boolean,
* withDescriptor: boolean,
* notOwn: (boolean|number),
* inverseFilter: boolean,
* type: string,
* async: boolean,
* thread: boolean,
* priority: (boolean|string),
* length: boolean
* }}
*/
ctx.info
— это ссылка на объект, который содержит информацию об исполняемой операции, т.е. с какими параметрами она запущена.
$C([1, 2, 3]).reverse.one.forEach((el, i, data, o) => {
/* {
filters: [],
mult: false,
async: false
count: false
endIndex: false
from: false
inverseFilter: false
length: true
live: false
notOwn: false
priority: false
reverse: true
startIndex: false
thread: false
type: 'array'
withDescriptor: false
} */
console.log(o.info);
});
/**
* @type {?}
*/
ctx.result
— это ссылка на значение результата операции, например, map.
$C([3, 2]).map((el, i, data, o) => {
console.log(o.result); // [6]
return el * 2;
});
/**
* @type {function(reset?: boolean): (number|Promise<number>)}
*/
Метод ctx.length
возвращает «длину» коллекции. Если метод вызван внутри обычной функции, то будут считаться только те
элементы, которые подходят по заданному фильтру (если таковой есть). По умолчанию результат кешируется, но
если нужно его сбросить, то следует передать в качестве первого параметра метода true
.
Метод возвращает либо число, либо промис (если исходная операция является асинхронной).
$C([1, 2, 3, 4, 5]).filter((el) => el > 2).map((el, i, data, o) => {
console.log(o.length()); // 3
return el * 2;
}) // [6, 8, 10]
/**
* @type {function(value?: number): (number|boolean)}
*/
Метод ctx.i
может возвращать номер текущей итерации (если не задан параметр value) или сдвигать итерационный курсор на заданное значение.
При сдвиге значения курсора метод вернёт новую позицию, однако, не все виды коллекций поддерживают такую операцию, например,
произвольный итератор или объект с учётом свойств прототипа не смогут менять значение итерационного курсора, а метод вернёт false
.
$C([1, 2, 3, 4, 5]).map((el, i, data, o) => {
o.i(1);
return el * 2;
}) // [2, 6, 10]
/**
* @type {function(value: number): (number|boolean)}
*/
Метод ctx.jump
задаёт новое значение итерационного курсора и возвращает его, а если это невозможно (операция не поддерживается коллекцией),
то метод вернёт false
.
$C([1, 2, 3, 4, 5]).map((el, i, data, o) => {
o.jump(o.length);
return el * 2;
}) // [2]
/**
* @type {number}
*/
Метод-геттер ctx.id
возвращает уникальный идентификатор итерации.
$C([1, 2, 3, 4, 5]).map((el, i, data, o) => {
if (o.id === 5) {
o.reset;
}
return el * o.id;
}) // [1, 4, 9, 16, 25, 6, 14, 24, 36, 50]
/**
* @type {FALSE}
* @readonly
*/
Метод-геттер ctx.reset
перезапускает всю текущую итерационную операцию заново, т.е. обход коллекции начинается сначала.
Метод возвращает значение ctx.false.
$C([1, 2, 3, 4, 5]).map((el, i, data, o) => {
if (o.result.length === data.length - 1) {
o.reset;
}
return el * 2;
}) // [2, 4, 6, 8, 10, 2, 4, 6, 8, 10]
/**
* @type {FALSE}
* @readonly
*/
Метод-геттер ctx.break
прерывает всю текущую итерационную операцию.
Метод возвращает значение ctx.false.
$C([1, 2, 3, 4, 5]).get((el, i, data, o) => el > 3 ? o.break : true) // [1, 2, 3]
/**
* @type {(Array|undefined)}
*/
ctx.childResult
— это ссылка массив результатов дочерних процессов асинхронной операции Collection.
$C([1, 5, 10]).async.forEach((el, i, data, o) => {
o.wait(1, $C(data).thread().reduce((res, el) => res + el, 0));
}, {
onIterationEnd(ctx) {
console.log(ctx.childResult); // [16, 16, 16]
}
})
/**
* @type {function(value?): boolean}
*/
Метод ctx.yield
приостанавливает выполнение асинхронной операции (по аналогии с оператором yield
в JS) и возвращает true
.
Если операция синхронная, то метод вернёт false
.
const obj = $C([1, 2]).async.forEach((el, i, data, o) => {
if (o.value) {
console.log(o.value) // 'Wake up!'
} else {
o.yield('I am sleep');
}
});
console.log(obj.thread.pause) // true
console.log(obj.thread.ctx.value) // 'I am sleep'
obj.thread.next('Wake up!');
/**
* @type {function(value?): boolean}
*/
Метод ctx.next
возобновляет выполнение асинхронной операции и возвращает true
.
Если операция синхронная, то метод вернёт false
.
var obj = $C([1, 2]).async.forEach((el, i, data, o) => {
if (!o.value) {
o.yield('I am sleep');
setTimeout(() => o.next('Wake up!'));
}
});
console.log(obj.thread.pause) // true
console.log(obj.thread.ctx.value) // 'I am sleep'
obj.then(() => {
console.log(obj.thread.ctx.value) // 'Wake up!'
});
/**
* @type {?}
* @readonly
*/
ctx.value
— это ссылка на значение переданное в yield или next.
const obj = $C([1, 2]).async.forEach((el, i, data, o) => {
if (o.value) {
console.log(o.value) // 'Wake up!'
} else {
o.yield('I am sleep');
}
});
console.log(obj.thread.ctx.value) // 'I am sleep'
obj.thread.next('Wake up!');
/**
* @type {function(thread): boolean}
*/
Метод ctx.child
помечает заданный поток как дочерний, т.е. при удалении основного потока будут также удалены все дочерние.
Если операция синхронная или заданный объект не является потоком Collection, то метод вернёт false
.
const obj = $C([new Array(1e8), new Array(1e8)]).async.forEach((el, i, data, o) => {
o.child($C(el).thread().reduce((sum, el, i) => sum + i, 0));
});
obj.thread.destroy();
/**
* @type {function(
* max: (number|Promise|function(): Promise),
* promise: (Promise|function(): Promise)
* ): Promise}
*/
Метод ctx.wait
помечает заданный поток или промис как дочерний. Также промис основной асинхронной операции не зарезолвится
пока не выполнятся все операции добавленные через этот метод, но при этом работа основной операции не блокируется.
Если метод используется с передачей двух параметров, то первым параметром является максимальное число одновременных дочерних операций
после превышения которого приостанавливается основная операция. В качестве ответа метод возвращает промис, а если операция синхронная false
.
$C([
'someURL1',
'someURL2',
'someURL3',
'someURL4',
'someURL5'
]).async.forEach((el, i, data, o) => {
// Одновременно открыты только 2 соединения с сервером
o.wait(2, fetch(el));
}).then(() => {
// Все запросы выполнены!
});
/**
* @type {function(
* max: (number|Promise|function(): Promise),
* promise: (Promise|function(): Promise)
* ): Promise}
*/
Метод ctx.race
помечает заданный поток или промис как дочерний. Также промис основной асинхронной операции не зарезолвится
пока не выполнится хотя бы одна операция добавленная через этот метод, но при этом работа основной операции не блокируется.
Если метод используется с передачей двух параметров, то первым параметром является максимальное число ожидаемых дочерних операций (по умолчанию 1
).
В качестве ответа метод возвращает промис, а если операция синхронная false
.
$C([
'someURL1',
'someURL2',
'someURL3',
'someURL4',
'someURL5'
]).async.forEach((el, i, data, o) => {
o.race(2, fetch(el));
}).then(() => {
// Гарантировано выполнено только 2 запроса
});
/**
* @type {function(
* time: number,
* test?: function(ctx): boolean,
* interval?: boolean
* ): (Promise|boolean)}
*/
Метод ctx.sleep
приостанавливает выполнение асинхронной операции на заданное количество миллисекунд.
Метод также может принимать 2 опциональных параметра:
-
test — функция, которая принимает в качестве параметра контекст операции и возвращает некоторое значение. Если возвращаемое значение положительное (
!= false && != null
), то итеративная функция «проснётся», а если отрицательное — нет. -
interval — если true, то в случае отрицательного результата test через time операция будет повторена (до тех пор пока не будет получен положительный результат).
В качестве ответа метод возвращает промис, а если операция синхронная false
.
/**
* @type {({
* thread: boolean,
* priority: string,
* destroy: function(),
* onComplete?: Function,
* onChunk?: Function,
* pause: boolean,
* sleep: ?,
* children: Array
* }|undefined)}
*/
ctx.thread
— это ссылка на объект потока Collection.
$C(new Array(1e9)).thread().map((el, i, data, o) => {
o.thread.priority = 'critical';
return i * 2;
});
/**
* @type {function(err)}
*/
ctx.onError
— это ссылка на функцию обработки ошибок Collection (используется при асинхронных операциях).
$C([1, 2, 3]).async.forEach((el, i, data, o) => {
o.sleep(1e3);
setTimeout(() => {
try {
bla.someMethod();
} catch (err) {
o.onError(err);
}
});
});