Skip to content

Контекст операции

Andrey edited this page Jan 18, 2018 · 13 revisions

Контекстом операции называется специальный объект, который содержит ряд методов и свойств для работы с исполняемой итеративной функцией.

/**
 * @typedef ctx
 * @typedef $$CollectionCtx
 */

Список методов и свойств

true

/**
 * @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]

false

/**
 * @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]

info

/**
 * @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);
});

result

/**
 * @type {?}
 */

ctx.result — это ссылка на значение результата операции, например, map.

$C([3, 2]).map((el, i, data, o) => {
  console.log(o.result); // [6]
  return el * 2;
});

length

/**
 * @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]

i

/**
 * @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]

jump

/**
 * @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]

id

/**
 * @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]

reset

/**
 * @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]

break

/**
 * @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]

childResult

/**
 * @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]
  }
})

yield

/**
 * @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!');

next

/**
 * @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!'
});

value

/**
 * @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!');

child

/**
 * @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();

wait

/**
 * @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(() => {
  // Все запросы выполнены!
});

race

/**
 * @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 запроса
});

sleep

/**
 * @type {function(
 *   time: number,
 *   test?: function(ctx): boolean,
 *   interval?: boolean
 * ): (Promise|boolean)}
 */

Метод ctx.sleep приостанавливает выполнение асинхронной операции на заданное количество миллисекунд. Метод также может принимать 2 опциональных параметра:

  • test — функция, которая принимает в качестве параметра контекст операции и возвращает некоторое значение. Если возвращаемое значение положительное (!= false && != null), то итеративная функция «проснётся», а если отрицательное — нет.

  • interval — если true, то в случае отрицательного результата test через time операция будет повторена (до тех пор пока не будет получен положительный результат).

В качестве ответа метод возвращает промис, а если операция синхронная false.

thread

/**
 * @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;
});

onError

/**
 * @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);
    }
  });
});