Это хук, который выполняется перед основным экшеном блока.
Если он кидает ошибку или же возвращает что-то отличное от undefined
,
то экшен не выполнятся и дальше выполняется хук options.error
или options.after соответственно.
Мы можем досрочно завершить выполнение блока:
- Вернув сразу какой-то результат.
- Вернуть ошибку.
- Вернуть результат или ошибку асинхронно (т.е. вернуть промис).
- Вернуть другой блок.
options: {
before: ( { deps } ) => {
if ( !deps[ id ].foo ) {
return {
foo: 42,
};
}
},
},
options: {
before: ( { params } ) => {
if ( !params.foo ) {
throw de.error( {
id: 'INVALID_PARAMS',
} );
}
},
},
options: {
before: ( { params } ) => {
if ( !params.foo ) {
return new Promise( ... );
}
},
},
Ждем, пока промис завершится. Дальше:
- Если он резолвится не
undefined
, то это результат работы блока. - Если он режектится, то это ошибка.
Последствия такие же, как и в синхронном варианте.
Если результат выполнения before
является блоком, то этот блок запускается с теми же параметрами
и его уже результат (успешный или нет) засчитывается как результат выполнения.
Этот другой блок опять таки может вернуть промис, другой блок, просто результат или кинуть ошибку.
Если before
кидает ошибку, то исполнения блока завершается.
Но иногда нужно завершить весь "запрос"
(по факту это не запрос, а запуск de.run). Произошла фатальная ошибка, нужен редирект и т.д.
const block = de.object( {
block: {
...
foo: de.object( {
block: de.block( {
...
options: {
before: ( { params, cancel } ) => {
if ( !params.foo ) {
// Тут мы не просто завершаем текущий блок,
// но и вообще все блоки, запущенные в этом de.run.
//
cancel.cancel( de.error( {
id: 'FATAL_ERROR',
} ) );
}
}
},
} ),
} ),
...
},
} );
try {
const result = await de.run( block, ... );
} catch ( e ) {
console.log( e );
// FATAL_ERROR
}
Подробнее про отмену выполнения
options: {
before: ( { params, context, deps, cancel } ) => {
},
},
В отличие от всех остальных хуков, здесь обратный порядок выполнения.
Сперва выполнятеся before
у потомка, а затем уже у родителя.
Потому что before
служит для того, чтобы досрочно завершить выполнение блока.
Если родительский before
не вернет undefined
, то выполнение блока завершится
и до before
потомка дело не дойдет совсем. И чтобы перекрыть это поведение,
before
у потомка должен вызываться до.
const parent = de.block( {
options: {
// ВНИМАНИЕ! Тут обратный порядок, в сравнении со всеми остальными хуками.
// Сперва вызывается before а потомка, а потом уже у родителя.
//
// Если он вернет что-то или бросит ошибку, то экшен блока вызываться не будет.
//
before: ( { params } ) => {
},
},
} );
const child = parent( {
options: {
// Сперва вызовется этот before.
// Если он вернет что-то или бросит ошибку,
// то выполнение блока завершится, before у родителя вызвано не будет.
//
params: ( { params } ) => {
return {
...params,
child: true,
};
},
},
} );
de.run( child, ... );