Skip to content

Latest commit

 

History

History
177 lines (130 loc) · 5.51 KB

options_before.md

File metadata and controls

177 lines (130 loc) · 5.51 KB

options.before

Это хук, который выполняется перед основным экшеном блока. Если он кидает ошибку или же возвращает что-то отличное от 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 является блоком, то этот блок запускается с теми же параметрами и его уже результат (успешный или нет) засчитывается как результат выполнения. Этот другой блок опять таки может вернуть промис, другой блок, просто результат или кинуть ошибку.

Завершить выполнение всего de.run

Если 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

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, ... );