Время на прочтение
4 мин
Количество просмотров 7.7K
Привет, когда разрабатываем любой проект на React, мы, при выборе что рендерить, больше всего имеем дело с условными операторами или просто с передачей компонентов в определенный компонент, функцию или тому подобное. Но если происходит неожиданная ситуация и в React компоненте или функции случается ошибка, то, зачастую мы видим белый экран смерти. И после этого нам надо открыть инструменты разработчика, чтобы увидеть в консоли ошибку. А это точно не лучший способ обработки ошибок.
Ошибки во время работы или белый экран с ошибками должны быть качественно обработаны. Для этого нам и понадобится React Error Boundary. В React добавили Error Boundary для отлавливания JavaScript ошибок и эффективной обработки их. Как сказано в react документации, Error Boundary — это компоненты React, которые отлавливают ошибки JavaScript в любом месте деревьев их дочерних компонентов, сохраняют их в журнале ошибок и выводят запасной UI вместо рухнувшего дерева компонентов. До дня, когда написана данная статья, react boundaries поддерживаются только как классовые компоненты. Следовательно, когда вы используете React с хуками, то это будет единственный классовый компонент, который вам понадобится.
Но хватит теории, давайте погружаться в код.
Давайте создадим классовый компонент, и используем его как error boundary. Вот код –
class ErrorBoundary extends Component {
state = {
error: null,
};
static getDerivedStateFromError(error) {
return { error };
}
render() {
const { error } = this.state;
if (error) {
return (
<div>
<p>Seems like an error occured!</p>
<p>{error.message}</p>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;
В коде выше вы увидите статичную функцию getDerivedStateFromError(error). Данная функция превращает классовый компонент ErrorBoundary в компонент, который действительно обрабатывает ошибки.
Мы отлавливаем ошибки внутри функции getDerivedStateFromError и помещаем их в состояние компонента. Если ошибка произошла, то мы отображаем её текст (пока что), а если нету, то просто возвращаем компонент, который должен отображаться.
Теперь, давайте посмотрим где мы можем использовать этот Error Boundary. Представьте, вы отображаете список пользователей, который получаете из API. Это выглядит примерно так –
const Users = ({ userData, handleMoreDetails }) => {
return (
<div>
<h1>Users List: </h1>
<ul>
{userData.map((user) => (
<div key={user.id}>
<p>Name: {user.name}</p>
<p>Company: {user.company}</p>
<button onClick={() => handleMoreDetails(user.id)}>
More details
</button>
</div>
))}
</ul>
</div>
);
};
Компонент User будет прекрасно работать, пока у нас всё в порядке с получением данных из userData. Но, если по какой-то причине userData будет undefined или null, наше приложение будет сломано! Так что, давайте добавим Error Boundary в данный компонент. После добавления наш код будет выглядеть вот так –
const Users = ({ userData, handleMoreDetails }) => {
return (
<div>
<h1>Users List: </h1>
<ErrorBoundary>
<ul>
{userData.map((user) => (
<div key={user.id}>
<p>Name: {user.name}</p>
<p>Company: {user.company}</p>
<button onClick={() => handleMoreDetails(user.id)}>
More details
</button>
</div>
))}
</ul>
</ErrorBoundary>
</div>
);
};
Когда ошибка произойдет, наш Error Boundary компонент отловит ошибку, и текст данной ошибки будет отображен на экране. Это спасет приложение от поломки, и пользователь поймет, что пошло не так.
Важный пункт, это выбрать, где мы используем Error Boundary, т.к. ошибка будет отображаться вместо компонента. Следовательно, нам нужно всегда быть уверенными, где будет отображаться текст данной ошибки. В нашем примере, мы хотим показывать верхнюю часть страницы, и все остальные данные. Нам всего лишь нужно заменить компонент, где ошибка произошла, и, в данной ситуации, это просто элемент ul. И мы выбираем использовать только ul элемент внутри Error Boundary, а не весь компонент целиком.
На текущий момент мы уже поняли, что такое Error Boundary и как использовать его. А вот наше место отображения ошибки выглядит не особо хорошо, и может быть улучшено. Способы, как мы отображаем ошибки и как “ломаются” наши компоненты будут отличаться от ситуации к ситуации. Так что нам надо сделать наш Error Boundary компонент более адаптивным к этим ситуациям.
Для этого мы создадим проп ErrorComponent внутри Error Boundary, и будем возвращать элемент, который прокиним внутрь данного пропа, чтобы он отображался во время ошибки. Ниже приведены финальный версии Error Boundary и User компонентов –
// User Component
const Users = ({ userData, handleMoreDetails }) => {
const ErrorMsg = (error) => {
return (
<div>
{/* Вы можете использовать свои стили и код для обработки ошибок */}
<p>Something went wrong!</p>
<p>{error.message}</p>
</div>
);
};
return (
<div>
<h1>Users List: </h1>
<ErrorBoundary ErrorComponent={ErrorMsg}>
<ul>
{userData.map((user) => (
<div key={user.id}>
<p>Name: {user.name}</p>
<p>Company: {user.company}</p>
<button onClick={() => handleMoreDetails(user.id)}>
More details
</button>
</div>
))}
</ul>
</ErrorBoundary>
</div>
);
};
// ErrorBoundary Component
class ErrorBoundary extends Component {
state = {
error: null,
};
static getDerivedStateFromError(error) {
return { error };
}
render() {
const { error } = this.state;
if (error) {
return <this.props.ErrorComponent error={error} />;
}
return this.props.children;
}
}
Вы можете также передавать проп key внутрь компонента Error Boundary, если вам нужно отображать несколько ошибок внутри одного компонента. Это позволит более гибко настроить данные ошибки для каждого элемента.
Error Boundary – это одна из приятных фишек React, которая, в свою очередь, я вижу что сравнительно редко используется. Но использование этого в вашем коде, будьте уверены, спасет вас от неловких моментов при внезапных ошибках. И кто не хочет лучше обрабатывать свои ошибки. 😉
В ситуации, когда вы не хотите писать свой собственный Error Boundary компонент, для этого можно использовать react-error-boundary.
А на этом пост заканчивается. Поделитесь своими мыслями в комментариях. И не забывайте, всегда продолжайте учиться!
Ирина Геннадьевна Молдавчук
Эксперт по предмету «1С:Бухгалтерия»
Задать вопрос автору статьи
Определение 1
Ошибка компоненты – это проблема, которая встречается при работе в системе 1С. Появиться такая ошибка может в разнообразных случаях: как при запуске программы, так и при работе в ней (при закрытии базы, месяца, выгрузке базы, при проведении документа, открытии справочника).
Выглядит данная ошибка следующим образом:
Рисунок 1. Ошибка компоненты. Автор24 — интернет-биржа студенческих работ
Сдай на права пока
учишься в ВУЗе
Вся теория в удобном приложении. Выбери инструктора и начни заниматься!
Получить скидку 4 500 ₽
Как видно из рисунка, особой информации данная ошибка в себе не содержит. Но чаще всего причиной появления данной ошибки является нарушение структуры базы данных. Другими словами, можно сказать, что появилась данная ошибка из-за аварийного закрытия программы. Аварийное закрытие программы может возникнуть по разным причинам, например, при отключении электричества или интернета, при неисправности компьютера или нехватке оперативной памяти.
Ошибку компоненты можно легко исправить. Для этого воспользуйтесь советами, представленными ниже.
Замечание 1
Перед началом исправления данной ошибки в обязательном порядке сделайте резервную копию базы данных!
Способы исправления
Обновление программы.
Самым простым способом исправления является обновление программы до последней версии. Если же у вас уже установлена последняя версия или вы не хотите обновлять программу, то в этом случае вам необходимо просто заменить файл «dbeng8.dll». Для этого возьмите этот файл из папки с другой установленной программой, которая может находиться как на вашем компьютере, так и на другом.
«Ошибка компоненты в 1С: причины и способы исправления» 👇
Очистка временных файлов.
Еще один из простых способов исправления ошибки, является очистка временных файлов. Данный вариант не совсем правильный, т.к. если удалить данные с ошибкой из списка и включить заново, при этом указав путь к базе, то кэш очистится, но ошибочные файлы, скорее всего, останутся на жестком диске.
Тестирование и исправление средствами конфигурации.
Для того чтобы воспользоваться данным способом в меню «Администрирование» выберите пункт «Тестирование и исправление…». После выбора данного пункта программа откроет напоминание о необходимости создания резервной копии данных. Затем вам нужно нажать на клавишу «Продолжить» и программа откроет форму с настройками. В графе «Проверки и режимы» вы найдете 6 пунктов, напротив, которых будут проставлены галочки.
Название и расшифровка проверок и режимов
Реиндексация таблиц – это перестройка индексов для таблиц БД, которая позволяет повысить производительность программы. Проверка логической целостности – происходит проверка связи новых таблиц с другими таблицами базы.
Проверка ссылочной целостности — производит проверку всех ссылок на разрушенные или не существующих объектов. Существует некоторое число вариантов действий, таких как сформировать объекты, зачищать ссылки или оставить без изменений. Оптимальным является выбор действия – формировать объекты.
Пересчет итогов. Все итоги программа хранит в отдельных таблицах и использует их для быстрого исчисления остатков или оборотов. В процессе работы появляется огромное число ненужных и лишних записей, которые приводят к медленному выполнению запросов. Также при сбое программа может неправильно отображать итоги.
Сжатие таблиц. Все данные, которые вы ранее помечали на удаление, программа продолжает хранить в базе. Данный пункт позволит удалить их окончательно.
Реструктуризация таблиц. Процесс, при котором программа пересоздает все таблицы с той же структурой БД. Это действенное средство в борьбе со сбоями в программе.
Замечание 2
Из всех перечисленных выше пунктов можно убрать галочки с: «Реиндексация таблиц информационной базы» и «Пересчет итогов». Эти два пункта никак не повлияют на исправление ошибки, но значительно увеличат время обработки данных.
После выбора пунктов нажмите на кнопку «Выполнить» и программа начнет процесс тестирования и исправления информационной базы. Такой процесс занимает достаточно длительное время. После завершения работы программа представит полный отчет.
Утилита «chdbfl.exe»
Утилита является заменой тестирования и исправления и предназначается для файловых информационных баз. Эта утилита поставляется совместно с программой 1С и находится в той же папке, что и библиотека, на которую ссылается исправляемая нами ошибка. Чаще всего найти утилиту можно: C:Program Files (x86)1cv828.2.18.96bin.
Когда вы найдете данную утилиту её необходимо запустить, путем открытия файла «chdbfl.exe». В открывшемся окне в поле «Имя файла БД» выберите файл «1Cv8.1CD».
В открытом окне утилиты установите галочку возле пункта «Исправлять обнаруженные ошибки». Это необходимо сделать для восстановления работоспособности информационной базы. По окончании своей работы утилита предоставит отчет о выполненных действиях.
Замечание 3
При использовании любого из способов необходимо проверять пропала ли данная ошибка.
Находи статьи и создавай свой список литературы по ГОСТу
Поиск по теме
Состояние тяжело поддерживать. Сложнее поддерживать пользовательский интерфейс. И почти невозможно сделать пользователя счастливым.
Независимо от того, насколько хорошо вы планируете, распад всегда происходит.
React — это хорошо известная библиотека веб-интерфейса с долгой историей реализации состояний. Компоненты формируют приложение. Но задача состояния — держать его в пределах разумного.
Если только это не сводит разработчика с ума до достижения этой цели!
Разные сезоны, разные состояния.
Мы знаем, как проходят времена года. Весной распускаются цветы. Летом по подмышкам стекает пот. Осенью листья падают с веток. А кто забудет снежные зимние дни? (Подсказка: дебют людей, живущих после глобального потепления!)
Природа может напоминать большую React Component
. Часть жизни на Земле. Но она проходит через различные фазы. Мы знаем каждый из них как сезон.
Различные части интерфейсного приложения также могут находиться на разных этапах. Они являются результатом изменений в том, что мы называем state
.
Введение в наше исследование.
Представьте себе человека с плохим характером. Он ругается жарким летом. И бьет людей, когда становится достаточно холодно. Никто не может его предсказать.
Можно сказать, что на него влияет погода.
Например, весной он добрый человек, а во время дождя даже стихи поет. Зимы холодные и вызывают у него радражительность. Вот почему он предпочтет заключать сделки действием, а не переговорами.
Такому человеку не хватает хорошего управления состоянием, что делает его неспособным контролировать свое поведение. Аналогичная проблема может существовать и во интерфейсном приложении. Вот когда он дает неуместные ответы или вообще не дает.
Затем давайте кратко рассмотрим, что такое состояние в компоненте React.
Состояние компонентов React.
Из документации React:
Состояние похоже на свойства, но является частным и полностью контролируется компонентом.
Props
сами по себе являются Objects
. Их keys
это имена attributes
которые мы передаем компоненту через JSX
. И их values
соответствуют значениям соответствующих атрибутов.
В то время как состояние может быть атрибутом или их коллекцией, оно может быть Object
, String
или любым другим JavaScript Type. Но в чем главное различие между состоянием и prop
?
Ответ: component
получает props
от своего родителя, в то время как он создает и controls
свое собственное state
.
В чем проблема?
Здесь мы можем задать вопрос: что делает приложение отличным?
Возможно преданность делу до конца. Желание доставить удовлетворение. Ощущение полезности. То, что мы можем назвать уверенностью.
Эти вещи не подталкивают плохое приложение. Оно уже чувствует себя довольным и уверенным. Его направляют на более солидные вещи. На это влияют потоки данных. По мощной инерции.
Оно не заботится об ожиданиях пользователей. И оно редко подходит для разных пользовательских историй. Работает, только если все в порядке. Что редко бывает в реальных приложениях.
Можем ли мы создать состояние, используя простую переменную?
Допустим, у нас есть компонент с именем Nature
. Этот компонент имеет основное переменное состояние: season
. Сначала давайте объявим это с помощью простого JavaScript variable
:
function Nature(props) {
let season = 'spring';
return(
<p>Currently it is {season}</p>
)
}
В строке const season = 'spring';
мы объявили нашу переменную состояния. Выходной HTML-код выглядит так:
<p>Currently it is spring</p>
Давайте добавим кнопку в возврат нашей функции. Мы передаем его событию обратный вызов onClick
, который попытается изменить значение переменной season
на «summer»:
function Nature(props) {
let season = 'spring';
const changeSeason = () => {
season = 'summer'
}
return(
<div>
<p>Currently it is {season}</p>
<button onClick={changeSeason}>Click to change season!</button>
</div>
)
}
Он выведет предыдущий результат с добавленной кнопкой. Тем не менее, если вы нажмете на кнопку, название сезона в выводе не изменится.
Значение переменной меняется на summer, но onClick
никогда не приведет к изменению выходных данных.
Почему?
Чтобы ответить на этот вопрос, мы должны узнать о React Hooks Flow
. Здесь все становится интересно.
Истории безумия компонентов.
События. Их последовательность формирует то, что мы можем назвать сюжетной линией. Например, вы могли только что закончить среднюю школу. Это важное событие для вас, которое также характеризует ваш уровень образования.
Наши воспоминания и личности состоят из событий. В наших резюме они полностью удовлетворены. И чтобы наша жизнь продолжалась, мы ожидаем и будущих событий.
Жизненный цикл компонента полон событий. Мы собираемся взглянуть на пример.
Предположим, что кнопка отправки используется для регистрации информации о пользователе. Кнопка неактивна, пока пользователь правильно не заполнит обязательные поля. Компонент формы использует переменную состояния для включения кнопки.
Работает отлично. Пользователь заполняет форму. Серая кнопка становится синей, и пользователь нажимает на нее. В фоновом режиме отправляется запрос API на регистрацию. Но пользователь не проинформирован. Они не видят никаких элементов загрузки или сообщений.
Они думают, что это не сработало, и снова нажимают на нее. И угадай что! Другой запрос отправляется в фоновом режиме. Первый запрос на регистрацию пользователя выполнен успешно.
Компонент предназначен для перенаправления пользователя в случае успеха. Но…
Ответ на второй запрос приходит в спешке. Подтверждение компонента, что электронная почта пользователя является дубликатом. Теперь другая переменная состояния, содержащая ошибку дублирования электронной почты, становится истинной.
Компонент выдает пользователю сообщение об ошибке, информирующее о том, что электронное письмо является дублированием, и перенаправление просто не работает, потому что состояние ошибки не является ложным. Компонент получил указание не перенаправлять, если состояние ошибки неясно. Что не имеет значения. И это плохое управлением состоянием.
В этом примере мы столкнулись с несколькими событиями. Один из них происходит при заполнении формы. Другой происходит, когда пользователь нажимает кнопку. Последнее событие — когда пришел ответ.
Мы, как пользователи и разработчики, можем понять эти события. Но UI-библиотека, такая как React, не так умна, как человек. Он должна быть проинструктирована о событиях и регистрировать их заранее.
Это то, что мы называем Components Hook Flow
.
Компоненты React Hook Flow
Хуки были добавлены в React с версии 16.8. В то время они были крупным обновлением, поскольку они наделили компоненты функций без сохранения состояния возможностями, которые были доступны только в компонентах класса.
Было хорошо иметь возможность запускать эффекты и изменять состояния в функциональном компоненте. Но компонент класса также предоставил разработчикам методы жизненного цикла, например componentDidMount или shouldComponentUpdate.
Функциональные компоненты и хуки не предоставляют нам методы жизненного цикла. Вместо этого разные хуки в функциональном компоненте запускаются в определенном порядке, чтобы разработчик мог реализовать одну и ту же логику жизненного цикла, учитывая этот порядок.
Hooks Flow состоит из 3 основных этапов: Mount
, Update
and Unmount
.
Когда компонент монтируется впервые, устанавливаются его начальные значения. К ним относятся функции инициализатора useState
и useReducer
. Затем он продолжит выполнение остальных кодов, которые вы добавили в свой функциональный компонент, до тех пор, пока не достигнет возвращенного значения.
Затем перед рендерингом возвращенного JSX он запустит ваш layoutEffects
, созданный с помощью хука useLayoutEffect
. Затем браузер рисует экран, чтобы отобразить React Virtual DOM. Затем вызываются effects
, которые вы зарегистрировали с помощью useEffect
.
Это простой процесс для установки компонента. Но тогда компонент нужно будет обновить. Это может произойти по двум причинам: либо изменились свойства, либо состояние было обновлено.
Этап обновления имеет свои собственные шаги: он запускает ваш функциональный компонент и обновляет DOM на основе новых изменений, возникающих в результате обновленного состояния.
На следующем шаге он очистит предыдущие эффекты layoutEffects, после чего запустит layoutEffects. Браузер перерисовывает экран, чтобы отразить изменения.
И, наконец, перед запуском эффектов react удалит предыдущие эффекты.
Этап обновления имеет тот же порядок шагов, что и этап монтажа. Отличается только деталями. Например, на этапе монтирования используются значения начального состояния, а на этапе обновления используются новые. На этапе монтирования запускаются эффекты, но сначала выполняется попытка устранить эффекты, вызванные предыдущими этапами обновления или монтирования компонента.
Третий этап в этом потоке, как мы уже упоминали, — это этап размонтирования. На этом этапе весь компонент будет удален с экрана. Так что ничего не произойдет, за исключением того, что React попытается очистить все оставшиеся эффекты и эффекты макета.
Теперь, когда мы знаем, как работает React Hooks Flow, мы можем понять, почему сохранение состояния нашего компонента внутри простой переменной не приведет к изменению DOM.
Потому что React не будет обновлять DOM, если не уверен, что что-то изменилось.
Способ, которым React прослушивает изменения состояния, похож на то, как мы можем добавить eventListeners в JS. Например, предположим, что это элемент ввода текста. Мы можем добавить слушателей для его value change
, или когда есть вход blurred
.
React добавляет слушателей к изменениям переменных состояния. И когда мы вызываем функции stateSetter, это событие запускается, и тогда React знает, как обновить DOM.
Затем давайте перепишем наш предыдущий код, чтобы он заработал.
Правильный способ объявить состояние
React предоставляет нам хук useState
для приведения состояний к функциональным компонентам. Чтобы инициализировать состояние, вам нужно вызвать хук и передать ему состояние initial value
.
Хук вернет массив из двух элементов. Первый элемент в массиве — это, state's value
, второй элемент — это state-setter function
.
Мы будем использовать эту функцию, чтобы добавить состояние сезона к нашему компоненту. Мы также перепишем нашу функцию changeSeason
, чтобы использовать функцию state-setter
, возвращаемую useState
.
function Nature(props) {
let [season, setSeason] = useState('spring');
const changeSeason = () => {
setSeason('summer')
}
return(
<div>
<p>Currently it is {season}</p>
<button onClick={changeSeason}>Click to change season!</button>
</div>
)
}
Теперь после рендеринга этого компонента, если мы попытаемся нажать на кнопку, мы увидим, что название сезона в абзаце изменится на summer
.
В приведенном выше коде переменная season
относится к первому элементу, возвращаемому useState, который содержит последнее значение состояния. А setSeason — это метод, который мы можем использовать для обновления значения состояния.
Мы узнали, как мы можем привести состояния к функциональному компоненту в React. И мы также узнали, как работают состояния в более фундаментальном смысле.
Зная, как правильно объявить состояние, возникает отличный вопрос: есть ли еще правильный способ использовать состояния в React?
Жизнь — это путешествие (как и разработка на React)
Никто не похож на других. Никто не разделяет те же интересы, что и другие. Мы все уникальны своими предпочтениями. И эта уникальность также влияет на то, как мы живем.
У разных проектов React тоже есть свои отличия. Они различаются тем, как они управляют своими состояниями, эффектами, деревьями компонентов или даже структурами папок.
Никто не заявляет, что вы должны структурировать проект React определенным образом. Вы должны понимать базовый образ мышления, который React использует для управления повторными рендерингами, реквизитами, состояниями, эффектами и т. д.
В этой статье мы узнали о том, как React реализует состояния. Надеюсь, это поможет вам лучше понять, что это такое и почему они важны.
Это уже длинная статья, и я закончу ее здесь, так как не хочу утомлять вас дополнительной информацией. Но позвольте мне добавить еще один совет. Каждый раз, когда вы сомневались, следует ли вам использовать состояние или нет, попробуйте ответить на этот вопрос: должны ли изменения в переменной вызывать повторный рендеринг?
Все хотят писать производительные, функциональные и при этом стабильные приложения. Но так как всем людям свойственно ошибаться, кода без ошибок не бывает. Независимо от уровня внимательности и количества написанных тестов всегда что-то может пойти не так. Поэтому с точки зрения пользовательского опыта важно предсказать появление проблемы, локализовать и устранить ее.
Рассмотрим обработку ошибок в React: что делать при их появлении, как их выявить и устранить.
Почему нужно находить ошибки в React
Начиная с 16-й версии React, возникающая во время жизненного цикла ошибка приводит к размонтированию всего приложения, если его не остановить. Ранее компоненты сохранялись на экране, даже если были искажены и не функционировали должным образом. Теперь уничтожить страницу полностью и отобразить пустой экран может досадная необнаруженная ошибка в незначительной части пользовательского интерфейса или даже в неконтролируемой разработчиком внешней библиотеке.
Выявление ошибок в JavaScript
В обычном JavaScript для выявления ошибок есть довольно простые инструменты. Например, оператор try/catch
: попытаться (try
) что-то выполнить, а если не получится, то поймать (catch
) ошибку и сделать что-нибудь, чтобы минимизировать ее последствия.
try {
// некорректная операция может вызвать ошибку
doSomething();
} catch (e) {
// если ошибка произошла, ловим ее и делаем что-нибудь без остановки приложения,
// например отправляем ее в службу регистрации
}
Для функции async
синтаксис будет такой же:
try {
await fetch('/bla-bla');
} catch (e) {
// Выборка не удалась! С этим нужно что-то делать!
}
Для традиционных промисов есть метод catch
. Предыдущий пример fetch
с API на основе промиса можно переписать так:
fetch('/bla-bla').then((result) => {
// Если промис выполнен успешно, результат будет здесь,
// с ним можно сделать что-нибудь полезное
}).catch((e) => {
// О нет, выборка не удалась! Нужно что-то с этим сделать!
})
Это та же концепция, только немного другая реализация, поэтому и далее для всех ошибок используем синтаксис try/catch
.
Простой try/catch в React: как правильно его выполнить
С пойманной ошибкой нужно что-то делать кроме того, чтобы записать ее куда-нибудь. Иначе говоря, что можно сделать, чтобы упростить жизнь пользователю? Не стоит оставлять его с пустым экраном или неработающим интерфейсом.
Наиболее очевидным и интуитивно понятным решением будет рендеринг на экране чего-либо до исправления ситуации. К счастью, оператор catch
предоставляет для этого ряд возможностей, включая установку состояния. Например:
const SomeComponent = () => {
const [hasError, setHasError] = useState(false);useEffect(() => {
try {
// делаем что-либо, например выборку данных
} catch(e) {
// выборка не прошла, данных для рендеринга нет!
setHasError(true);
}
})// что-то произошло во время выборки, отобразим красивый экран с ошибкой
if (hasError) return <SomeErrorScreen />// данные есть - отрендерим их
return <SomeComponentContent {...datasomething} /
Мы пытаемся отправить запрос на выборку данных. В случае неудачи устанавливаем состояние ошибки и, если оно равно true
, отображаем экран ошибки с дополнительной информацией для пользователя, например номером службы поддержки.
Этот способ подходит для простых, предсказуемых и ограниченных вариантов использования, таких как обнаружение неудачного запроса fetch
.
Но если вы захотите отловить все возможные варианты ошибок в компоненте, то столкнетесь с определенными проблемами и серьезными ограничениями.
Ограничение 1: проблемы с хуком useEffect
Если просто обернуть useEffect
с помощью try/catch
, это не сработает:
try {
useEffect(() => {
throw new Error('Hulk smash!');
}, [])
} catch(e) {
// useEffect выбрасывается, но не вызывается
}
Дело в том, что useEffect
вызывается асинхронно после рендеринга, поэтому для try/catch
все проходит успешно. Подобное происходит и с любым Promise: если не ожидать результата, JavaScript просто продолжит свое дело, вернется к нему, когда промис будет выполнен, и выполнит только то, что находится внутри useEffect
(и затем промиса). Выполненный блок try/catch
исчезнет к тому времени.
Чтобы отлавливать ошибки внутри useEffect
, нужно также поместить try/catch
внутрь:
useEffect(() => {
try {
throw new Error('Hulk smash!');
} catch(e) {
// эта ошибка будет перехвачена
}
}, [])
Поэкспериментируйте с этим примером.
Это относится к любому хуку, использующему useEffect
, и ко всем асинхронным действиям. В результате вместо одного try/catch
, обертывающего все, придется разбить его на несколько блоков: по одному на каждый хук.
Ограничение 2: дочерние компоненты
try/catch
не сможет поймать ошибку внутри дочерних компонентов. Например:
const Component = () => {
let child;try {
child = <Child />
} catch(e) {
// бесполезен для отлова ошибок внутри дочернего компонента, не будет запускаться
}
return child;
}
Или даже так:
const Component = () => {
try {
return <Child />
} catch(e) {
// по-прежнему бесполезен для обнаружения ошибок внутри дочернего компонента, не будет запускаться
}
}
Убедитесь на этом примере.
После Child />
нет реального рендеринга компонента. Мы создаем Element
компонента, который является его определением. Это просто объект, который содержит необходимую информацию, такую как тип компонента и реквизиты, которые позже будут использоваться самим React, что фактически и вызовет рендеринг этого компонента. И произойдет это после успешного выполнения блока try/catch
. Та же ситуация, что с промисами и хуком useEffect
.
Ограничение 3: нельзя установить состояние во время рендеринга
Если попытаться отловить ошибки вне useEffect
и различных обратных вызовов (т. е. во время рендеринга компонента), то разобраться с ними должным образом уже не так просто: обновления состояния во время рендеринга не допускаются.
Вот пример простого кода, который вызовет бесконечный цикл повторных рендеров, если произойдет ошибка:
const Component = () => {
const [hasError, setHasError] = useState(false);try {
doSomethingComplicated();
} catch(e) {
// недопустимый вариант! В случае ошибки вызовет бесконечный цикл
// см. реальный пример в codesandbox ниже
setHasError(true);
}
}
Убедитесь сами в codesandbox.
Конечно, можно просто отобразить экран ошибки вместо установки состояния:
const Component = () => {
try {
doSomethingComplicated();
} catch(e) {
// допустимый вариант
return <SomeErrorScreen />
}
}
Но это немного громоздко и заставит по-разному обрабатывать ошибки в одном и том же компоненте: состояние для useEffect
и обратных вызовов, а также прямой возврат для всего остального.
// это рабочий, но громоздкий вариант, не заслуживающий внимания
const SomeComponent = () => {
const [hasError, setHasError] = useState(false);useEffect(() => {
try {
// делаем что-либо, например выборку данных
} catch(e) {
// невозможен простой return в случае ошибок в useEffect и callbacks,
// поэтому приходится использовать состояние
setHasError(true);
}
})try {
// делаем что-либо во время рендеринга
} catch(e) {
// но здесь мы не можем использовать состояние, поэтому в случае ошибки нужно возвращать напрямую
return <SomeErrorScreen />;
}// и все же нужен return в случае ошибки состояния
if (hasError) return <SomeErrorScreen />
return <SomeComponentContent {...datasomething} />
}
В итоге, если в React полагаться исключительно на try/catch
, то мы либо пропустим большую часть ошибок, либо превратим каждый компонент в непонятную смесь кода, которая, вероятно, сама по себе вызовет ошибки.
К счастью, есть и другой способ.
Компонент React ErrorBoundary
Обойти отмеченные выше ограничения позволяет React Error Boundaries. Это специальный API, который превращает обычный компонент в оператор try/catch
в некотором роде только для декларативного кода React. Типичное использование будет примерно таким:
const Component = () => {
return (
<ErrorBoundary>
<SomeChildComponent />
<AnotherChildComponent />
</ErrorBoundary>
)
}
Теперь, если в этих компонентах или их дочерних элементах что-то пойдет не так во время рендеринга, ошибка будет обнаружена и обработана.
Но React не предоставляет компонент как таковой, а просто дает инструмент для его реализации. Простейшая реализация будет примерно такой:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
// инициализировать состояние ошибки
this.state = { hasError: false };
}// если произошла ошибка, установите состояние в true
static getDerivedStateFromError(error) {
return { hasError: true };
}render() {
// если произошла ошибка, вернуть резервный компонент
if (this.state.hasError) {
return <>Oh no! Epic fail!</>
}return this.props.children;
}
}
Мы создаем компонент класса regular
и реализуем метод getDerivedStateFromError
, который возвращает компонент в надлежащие границы ошибок.
Кроме того, при работе с ошибками важно отправить информацию о них в сервис обработки. Для этого в Error Boundary есть метод componentDidCatch
:
class ErrorBoundary extends React.Component {
// все остальное остается прежнимcomponentDidCatch(error, errorInfo) {
// отправить информацию об ошибке
log(error, errorInfo);
}
}
После настройки границ ошибок с ними можно работать, как и с любым другим компонентом. Например, можно сделать его более пригодным для повторного использования и передать резервный вариант в качестве реквизита:
render() {
// если произошла ошибка, вернуть резервный компонент
if (this.state.hasError) {
return this.props.fallback;
}return this.props.children;
}
Используем таким образом:
const Component = () => {
return (
<ErrorBoundary fallback={<>Oh no! Do something!</>}>
<SomeChildComponent />
<AnotherChildComponent />
</ErrorBoundary>
)
}
Можно выполнять и другие задачи, например сброс состояния при нажатии кнопки, дифференциацию ошибок по типам и отправку ошибки в контекст.
Полный пример в codesandbox.
Однако есть одно предостережение: улавливаются не все ошибки.
Компонент ErrorBoundary: ограничения
ErrorBoundary
улавливает только те ошибки, которые возникают во время жизненного цикла React. Все происходящее за его пределами, включая разрешенные промисы, асинхронный код с setTimeout
, различные обратные вызовы и обработчики событий, просто исчезнет, если не будут обработано явно.
const Component = () => {
useEffect(() => {
// будет пойман компонентом ErrorBoundary
throw new Error('Destroy everything!');
}, [])const onClick = () => {
// эта ошибка просто исчезнет в void
throw new Error('Hulk smash!');
}useEffect(() => {
// если это не сработает, ошибка тоже исчезнет
fetch('/bla')
}, [])
return <button onClick={onClick}>click me</button>
}const ComponentWithBoundary = () => {
return (
<ErrorBoundary>
<Component />
</ErrorBoundary>
)
}
Общей рекомендацией для ошибок такого рода является использование обычных try/catch
. По крайней мере здесь мы можем более или менее безопасно использовать состояние: обратные вызовы обработчиков событий — это как раз те места, где обычно устанавливают состояние. Итак, технически можно просто объединить два подхода, например:
const Component = () => {
const [hasError, setHasError] = useState(false);// большинство ошибок в этом и в дочерних компонентах будут перехвачены ErrorBoundary
const onClick = () => {
try {
// эта ошибка будет поймана catch
throw new Error('Hulk smash!');
} catch(e) {
setHasError(true);
}
}if (hasError) return 'something went wrong';
return <button onClick={onClick}>click me</button>
}const ComponentWithBoundary = () => {
return (
<ErrorBoundary fallback={"Oh no! Something went wrong"}>
<Component />
</ErrorBoundary>
)
}
Мы вернулись к исходной ситуации: каждый компонент должен поддерживать свое состояние «ошибка» и, что более важно, принимать решение о том, что с ним делать.
Конечно, вместо того чтобы обрабатывать эти ошибки на уровне компонентов, можно просто передавать их до родителя, у которого есть ErrorBoundary
, через пропсы или Context
. Таким образом, по крайней мере можно иметь «резервный» компонент только в одном месте:
const Component = ({ onError }) => {
const onClick = () => {
try {
throw new Error('Hulk smash!');
} catch(e) {
// просто вызовите пропс вместо сохранения здесь состояния
onError();
}
}return <button onClick={onClick}>click me</button>
}const ComponentWithBoundary = () => {
const [hasError, setHasError] = useState();
const fallback = "Oh no! Something went wrong";if (hasError) return fallback;
return (
<ErrorBoundary fallback={fallback}>
<Component onError={() => setHasError(true)} />
</ErrorBoundary>
)
}
Но здесь много дополнительного кода! Так пришлось бы делать для каждого дочернего компонента в дереве рендеринга. Не говоря уже о том, что сейчас мы обрабатываем два состояния ошибки: в родительском компоненте и в самом ErrorBoundary
. А у ErrorBoundary
уже есть все механизмы для распространения ошибок вверх по дереву — здесь мы делаем двойную работу.
Разве нельзя просто перехватывать эти ошибки из асинхронного кода и обработчиков событий с помощью ErrorBoundary
?
Поиск асинхронных ошибок с помощью ErrorBoundary
Хитрость заключается в том, чтобы сначала поймать ошибки с помощью try/catch
, затем внутри оператора catch
запустить обычную повторную визуализацию React, а затем повторно отбросить эти ошибки обратно в жизненный цикл повторной визуализации. Таким образом, ErrorBoundary
может перехватывать их, как и любую другую ошибку. И поскольку обновление состояния — это способ запуска повторного рендеринга, а функция установки состояния может фактически принимать функцию обновления в качестве аргумента, решение — чистая магия.
const Component = () => {
// создать случайное состояние, которое будем использовать для выдачи ошибок
const [state, setState] = useState();const onClick = () => {
try {
// возникла какая-то проблема
} catch (e) {
// обновление состояния триггера с функцией обновления в качестве аргумента
setState(() => {
// повторно выдать эту ошибку в функции обновления
// будет запущено во время обновления состояния
throw e;
})
}
}
}
Полный пример в этом codesandbox.
Последним шагом будет абстрагирование этого сокращения, поэтому нам не нужно создавать случайные состояния в каждом компоненте. Здесь можно проявить творческий подход и создать хук, который создаст генератор асинхронных ошибок:
const useThrowAsyncError = () => {
const [state, setState] = useState();return (error) => {
setState(() => throw error)
}
}
Используем так:
const Component = () => {
const throwAsyncError = useThrowAsyncError();useEffect(() => {
fetch('/bla').then().catch((e) => {
// выдать асинхронную ошибку здесь
throwAsyncError(e)
})
})
}
Или можно создать оболочку для обратных вызовов следующим образом:
const useCallbackWithErrorHandling = (callback) => {
const [state, setState] = useState();return (...args) => {
try {
callback(...args);
} catch(e) {
setState(() => throw e);
}
}
}
Используем так:
const Component = () => {
const onClick = () => {
// выполнить что-либо опасное здесь
}const onClickWithErrorHandler = useCallbackWithErrorHandling(onClick);
return <button onClick={onClickWithErrorHandler}>click me!</button>
}
Или что-нибудь еще, что душе угодно и требуется приложению. Ошибки теперь не спрячутся.
Полный пример в этом codesandbox.
Можно ли использовать react-error-boundary?
Для тех, кто не любит изобретать велосипед или просто предпочитает библиотеки для уже решенных задач, есть хороший вариант, который реализует гибкий компонент ErrorBoundary
и имеет несколько полезных утилит, подобных описанным выше. Это — react-error-boundary.
Использовать его или нет — вопрос личных предпочтений, стиля программирования и уникальных особенностей компонентов.
Теперь, если в приложении возникнет проблема, вы сможете легко с ней справиться.
И запомните:
- Блоки
try/catch
не будут перехватывать ошибки внутри хуков, таких какuseEffect
, и внутри любых дочерних компонентов. ErrorBoundary
их перехватывать может, но не работает с ошибками в асинхронном коде и в обработчиках событий.- Тем не менее вы можете заставить
ErrorBoundary
ловить их. Просто сначала их нужно поймать с помощьюtry/catch
, а затем забросить обратно в жизненный цикл React.
Читайте также:
- Управление состоянием в React: обзор
- 9 советов по работе с консолью JavaScript, которые помогут оптимизировать отладку
- Preact вместо ручной оптимизации React-приложения
Читайте нас в Telegram, VK и Дзен
Перевод статьи Nadia Makarevich: How to handle errors in React: full guide
Если мы исходим из предположения, что в программном обеспечении будут ошибки, то, очевидно, в первую очередь следует принять меры для их обнаружения. Более того, если необходимо принимать дополнительные меры (например, исправлять ошибки или их последствия), то все равно сначала нужно уметь обнаруживать ошибки.
Меры по обнаружению ошибок можно разбить на две подгруппы:
пассивные попытки обнаружить симптомы ошибки в процессе «обычной» работы программного обеспечения и активные попытки программной системы периодически обследовать свое состояние в поисках признаков ошибок.
Пассивное обнаружение ошибок
Меры по обнаружению ошибок могут быть приняты на нескольких структурных уровнях программной системы. Нас интересуют меры по обнаружению симптомов ошибок, предпринимаемые при переходе от одной компоненты к другой, а также внутри компоненты. Все это, конечно, применимо также к отдельным модулям внутри компоненты.
Разрабатывая эти меры, мы будем опираться на следующие положения:
1. Взаимное недоверие. Каждая из компонент должна предполагать, что все другие содержат ошибки. Когда она получает какие-нибудь данные от другой компоненты или из источника вне системы, она должна предполагать, что данные могут быть неправильными, и пытаться найти в них ошибки.
2. Немедленное обнаружение. Ошибки необходимо обнаружить как можно раньше. Это не только ограничивает наносимый ими ущерб, но и значительно упрощает задачу отладки.
3. Избыточность. Все средства обнаружения ошибок основаны на некоторой форме избыточности (явной или неявной).
Конкретные меры обнаружения сильно зависят от специфики прикладной области. Однако некоторые идеи можно почерпнуть из следующего списка:
· Проверяйте атрибуты любого элемента входных данных. Если входные данные должны быть числовыми или буквенными, проверьте это. Если число на входе должно быть положительным, проверьте его значение. Если известно, какой должна быть длина входных данных, проверьте ее.
· Применяйте «тэги» в таблицах, записях и управляющих блоках и проверяйте с их помощью допустимость входных данных. Тэг — это поле записи, явно указывающее на ее назначение.
· Проверяйте, находится ли входное значение в установленных пределах. Например, если входной элемент — адрес в основной памяти, проверяйте его
допустимость. Всегда проверяйте поле адреса или указателя на нуль и считайте, что оно неверно, если равно нулю. Если входные данные — таблица вероятностей, проверьте, находятся ли все значения между нулем и единицей.
· Проверяйте допустимость всех вариантов значений. Если входное поле — код, обозначающий один из десяти районов, никогда не предполагайте, что если это не код ни одного из районов 1, 2,…, 9, то это обязательно код района 10.
· Если во входных данных есть какая-либо явная избыточность, воспользуйтесь ею для проверки данных.
· Там, где во входных данных нет явной избыточности, введите ее. Если ваша система использует крайне важную таблицу, подумайте о включении в нее контрольной суммы. Всякий раз, когда таблица обновляется, следует просуммировать (по некоторому модулю) ее поля и результат поместить в специальное поле контрольной суммы. Подсистема, использующая таблицу, сможет теперь проверить, не была ли таблица случайно испорчена, — для этого только нужно выполнить контрольное суммирование.
· Сравнивайте, согласуются ли входные данные с какими-либо внутренними данными. Если на входе операционной системы возникает требование освободить некоторый блок памяти, она должна убедиться, что этот блок в данный момент действительно занят.
Когда разрабатываются меры по обнаружению ошибок, важно принять согласованную стратегию для всей системы (т.е. применить идею концептуальной целостности). Действия, предпринимаемые после обнаружения ошибки в программном обеспечении (например, возврат кода ошибки), должны быть единообразными для всех компонент системы. Это ставит вопрос о том, какие именно действия следует предпринять, когда ошибка обнаружена. Наилучшее решение — немедленно завершить выполнение программы или (в случае операционной системы) перевести ЦП в состояние ожидания. С точки зрения предоставления человеку, отлаживающему программу, например системному программисту, самых благоприятных условий для диагностики ошибок немедленное завершение представляется наилучшей стратегией. Конечно, во многих системах подобная стратегия бывает нецелесообразной (например, может оказаться, что приостанавливать работу системы нельзя). В таком случае используется метод регистрации ошибок. Описание симптомов ошибки и «моментальный снимок» состояния системы сохраняется во внешнем файле, после чего система может продолжать работу. Этот файл позднее будет изучен обслуживающим персоналом. Такой метод использован в операционной системе OS/VS2MVS фирмы IBM. Каждая компонента содержит программу восстановления, которая перехватывает все случаи ненормального
завершения и программные прерывания в этой компоненте и регистрирует данные об ошибке во внешнем файле.
Всегда, когда это возможно, лучше приостановить выполнение программы, чем регистрировать ошибки (либо обеспечить как дополнительную возможность работу системы в любом из этих режимов). Различие между этими методами проиллюстрируем на способах выявления причин возникающего иногда скрежета вашего автомобиля. Если автомеханик находится на заднем сиденье, то он может обследовать состояние машины в тот момент, когда скрежет возникает. Если же вы выбираете метод регистрации ошибок (записывая скрежет на магнитофон), задача диагностики будет значительно сложнее.
Пример: система PRIME
Система PRIME-это мультипроцессорная система с виртуальной памятью, разработанная в Калифорнийском университете в Беркли. Один из процессоров системы выделен в качестве центрального процессора и содержит центральный управляющий монитор (ССМ — central control monitor) — управляющую программу, которая распределяет страницы памяти и пространство на диске, назначает программы другим процессорам (проблемным процессорам) и регулирует пересылки всех межпроцессорных сообщений. Расширенный управляющий монитор (ЕСМ — extended control monitor) — это реализованная микропрограммно-управляющая программа, постоянно присутствующая в каждом процессоре и управляющая диспетчеризацией процессов, операциями ввода-вывода и посылки / получения.
Защита данных — одна из основных целей системы. В этом направлении в системе PRIME сделан шаг вперед по сравнению с большинством других систем: в дополнение к обеспечению защиты в нормальных условиях ставится цель гарантировать защиту даже при наличии отдельной ошибки в программном обеспечении или отдельного сбоя аппаратуры. Меры по обнаружению ошибок составляют основу метода достижения этой цели.
Во время разработки системы PRIME были явно выделены все принимаемые операционной системой решения, ошибки в которых могут привести к тому, что данные одного пользователя станут доступными другому пользователю или его программе. Были реализованы средства обнаружения ошибок для каждого из этих решений.
Многие из них представляют собой комбинацию аппаратных и программных средств. Например, всякий раз, когда процессу пользователя выделяется терминал, ССМ запоминает идентификатор этого процесса в регистре терминала. Когда ЕСМ посылает данные на терминал, тот всегда сравнивает хранимый идентификатор с идентификатором при посланных данных. Последнее гарантирует, что отдельная ошибка в программном обеспечении или сбой аппаратуры не приведут к печати данных не на том терминале.
Система PRIME содержит механизм посылки / получения, который позволяет процессу одного пользователя послать сообщение процессу другого пользователя. Для этого процесс-отправитель передает своему ЕСМ это сообщение и идентификатор процесса-получателя. ЕСМ добавляет идентификатор отправителя и передает сообщение ССМ. Тот передает сообщение ЕСМ процессора, содержащего процесс-получатель, а ЕСМ наконец передает сообщение указанному процессу пользователя. В этой последовательности выполняются три проверки с целью обнаружения ошибки. ССМ проверяет, правильный ли идентификатор процесса-отправителя добавлен ЕСМ; он может это сделать, поскольку известно, какому пользователю выделен процессор. ЕСМ адресата проверяет, тому ли процессору ССМ направил сообщение; он выполняет это, сравнивая идентификатор процесса в сообщении с идентификатором процесса, которому в данный момент выделен процессор. Третья проверка делается для обеспечения сохранности сообщения при транзите. ЕСМ-отправитель формирует для сообщения контрольную сумму и передает ее вместе с сообщением. ЕСМ-получатель вычисляет контрольную сумму доставленного сообщения и сравнивает с извлеченной из сообщения.
В качестве примера другой проверки отметим, что ССМ распределяет свободные страницы памяти между процессами пользователей и хранит список свободных страниц. Когда страница больше не нужна ЕСМ, он помечает ее и сообщает ССМ, чтобы тот включил ее в список свободных. Получая очередную выделенную страницу, ЕСМ проверяет пометку на ней, чтобы убедиться, что страница действительно свободна. Эта избыточность может быть использована для обнаружения ошибок, потому что список свободных страниц обрабатывается ССМ, а помечают страницы другие процессоры.
Активное обнаружение ошибок
Не все ошибки можно выявить пассивными методами, поскольку эти методы обнаруживают ошибку лишь тогда, когда ее симптомы подвергаются соответствующей проверке. Можно делать и дополнительные проверки, если спроектировать специальные программные средства для активного поиска признаков ошибок в системе. Такие средства называются средствами активного обнаружения ошибок.
Активные средства обнаружения ошибок обычно объединяются в диагностический монитор: параллельный процесс, который периодически анализирует состояние системы с целью обнаружить ошибку. Большие программные системы, управляющие ресурсами, часто содержат ошибки, приводящие к потере ресурсов на длительное время. Например, управление памятью операционной системы сдает блоки памяти «в аренду» программам пользователей и другим частям операционной системы. Ошибка в этих самых «других частях» системы может иногда вести к неправильной работе блока управления памятью,
занимающегося возвратом сданной ранее в аренду памяти, что вызывает медленное вырождение системы.
Диагностический монитор можно реализовать как периодически выполняемую задачу (например, она планируется на каждый час) либо как задачу с низким приоритетом, которая планируется для выполнения в то время, когда система переходит в состояние ожидания. Как и прежде, выполняемые монитором конкретные проверки зависят от специфики системы, но некоторые идеи будут понятны из примеров. Монитор может обследовать основную память, чтобы обнаружить блоки памяти, не выделенные ни одной из выполняемых задач и не включенные в системный список свободной памяти. Он может проверять также необычные ситуации: например, процесс не планировался для выполнения в течение некоторого разумного интервала времени. Монитор может осуществлять поиск «затерявшихся» внутри системы сообщений или операций ввода-вывода, которые необычно долгое время остаются незавершенными, участков памяти на диске, которые не помечены как выделенные и не включены в список свободной памяти, а также различного рода странностей в файлах данных.
Иногда желательно, чтобы в чрезвычайных обстоятельствах монитор выполнял диагностические тесты системы. Он может вызывать определенные системные функции, сравнивая их результат с заранее определенным и проверяя, насколько разумно время выполнения. Монитор может также периодически предъявлять системе «пустые» или «легкие» задания, чтобы убедиться, что система функционирует хотя бы самым примитивным образом.
Пример: программа обнаружения разрушений, разработанная фирмой TRW
Система защиты ресурсов фирмы IBM — это экспериментальная модификация операционной системы OS/360 для изучения проблем, связанных с системами защиты. Используя ее, корпорация TRW разработала монитор, действующий в заранее установленные интервалы времени и пытающийся обнаружить признаки того, что программа пользователя нарушила правила защиты.
Этот монитор проверяет много различных условий. Большинство из них характерно именно для OS/360 и поэтому интересны не для всех. В качестве некоторых примеров, можно, однако, указать, что монитор определяет, вся ли управляющая информация OS/3CO о задачах пользователя хранится в защищенной области памяти. Монитор также проверяет, всели программы пользователя выполняются в режиме задачи и вся ли память пользователя защищена от выборки соответствующим ключом защиты. Монитор контролирует правильность соблюдения очереди ожидающими операциями ввода-вывода и гарантирует, что точки входа для всех прерываний являются соответствующими входами OS/360 и что вся память супервизора надлежащим образом
защищена. Как только обнаруживается какое-то несоответствие, немедленно выдается сообщение оператору.