это несколькоfeature
Магический эффект, достигаемый при совместном применении, вReact
Он широко используется в исходном коде.
Когда я прочитал исходный код и увидел это, мое настроение изменилось:
Сбит с толку -- Сбит с толку -- Задумчив -- Проверяю документацию -- Внезапно просветлен
Прочитав эту статью, я думаю, вы тоже вздохнете:
Ты еще можешь так играть?
источник
мы знаем,React
Есть особенность вError Boundary
, помогите нам в组件
Пользовательский интерфейс, который отображает «Статус ошибки» при возникновении ошибки.
Для реализации этой функции необходимо отлавливать ошибки.
так вReact
В исходном коде все用户代码
Все завернуто в метод.
Аналогично следующему:
function wrapper(func) {
try {
func();
} catch(e) {
// ...处理错误
}
}
например, запускcomponentDidMount
Время:
wrapper(componentDidMount);
Все было идеально, ноReact
Как интерфейсный фреймворк мирового уровня, он имеет широкую аудиторию и уделяет внимание максимальному во всем.
Нет, кто-то поднял вопрос:
Вы здесь
try catch
выполнить в用户代码
позволит инструментам отладки браузераPause on exceptions
неверный.
Плюсы и минусы паузы при сбое исключений
Pause on exceptions
что это такое?
Он инструмент отладки браузераsource
Функция панели.
После включения этой функции, когда во время выполнения встречается код, выдающий ошибку, выполнение кода автоматически останавливается на этой строке, как если бы на этой строке была установлена точка останова.
Например, выполните следующий код и включите эту функцию:
let a = c;
Выполнение кода будет приостановлено на этой строке.
Эта функция может быть очень удобной, чтобы помочь нам найти未捕获的错误
место, где это произошло.
Однако, когдаReact
Буду用户代码
завернут вtry catch
, даже если код выдаст ошибку, это будетcatch
.
Pause on exceptions
не могу выкинуть ошибку用户代码
приостановлено, потому чтоerror
БылReact
catch
.
если мы не откроем дальшеPause on caught exceptions
.
Включите эту функцию, чтобы код в捕获的错误
Место, где произошла пауза.
Как решить
Для пользователя я пишу вcomponentDidMount
Код явно не ловит ошибку, но когда ошибка возникаетPause on exceptions
Это не работает, что действительно сбивает с толку.
Итак, в производственных условияхReact
продолжать использоватьtry catch
выполнитьwrapper
.
В среде разработки для лучшего опыта отладки необходимо повторно реализовать наборtry catch
механизм, включающий следующие функции:
-
захватывать
用户代码
выдает ошибку так чтоError Boundary
Функция работает -
не захватывать
用户代码
выдает ошибку так чтоPause on exceptions
недействительный
Эта, казалось бы, противоречивая функция,React
Как сделать это с умом?
Как «ловить» ошибки
Давайте сначала реализуем первый пункт: захват用户代码
Ошибка выброшена.
но не могу использоватьtry catch
, потому что это сделало быPause on exceptions
неверный.
Решение: мониторwindow
изerror
мероприятие.
согласно сGlobalEventHandlers.onerror MDN, событие может прослушивать два типа ошибок:
-
js ошибки времени выполнения (включая синтаксические ошибки).
window
вызоветErrorEvent
интерфейсerror
мероприятие -
ресурсы (например,
<img>
или<script>
) не удалось загрузить ошибку. Элемент, который загружает ресурс, сработаетEvent
интерфейсerror
события, которые могут бытьwindow
поймать ошибку на
реализация среды разработкиwrapperDev
:
// 开发环境wrapper
function wrapperDev(func) {
function handleWindowError(error) {
// 收集错误交给Error Boundary处理
}
window.addEventListener('error', handleWindowError);
func();
window.removeEventListener('error', handleWindowError);
}
когдаfunc
Во время выполнения выдается ошибка, она будетhandleWindowError
иметь дело с.
Однако по сравнению с производственной средойwrapperPrd
Внутриfunc
Выданная ошибка будетcatch
, не повлияет на последующее выполнение кода.
function wrapperPrd(func) {
try {
func();
} catch(e) {
// ...处理错误
}
}
среда разработкиfunc
При возникновении ошибки выполнение кода будет прервано.
Например, выполните следующий код,finish
будет напечатано.
wrapperPrd(() => {throw Error(123)})
console.log('finish');
Но при выполнении следующего кода выполнение кода прерывается,finish
не будет напечатано.
wrapperDev(() => {throw Error(123)})
console.log('finish');
как не поймать用户代码
Как можно не прерывать выполнение последующего кода, если возникает ошибка?
Как обеспечить бесперебойное выполнение кода
Ответ: черезdispatchEvent
вызывать事件回调
,существует回调
вызывать用户代码
.
согласно сEventTarget.dispatchEvent MDN:
отличный отDOM
События, запускаемые узлом (например,click
событие) обратный вызов выполняетсяevent loop
Запускается асинхронно.
пройти черезdispatchEvent
Инициированное событие запускается синхронно и вызывается в обратном вызове события.错误
Это не повлияетdispatchEvent
звонивший из .
Продолжаем трансформироватьсяwrapperDev
.
Сначала создайте фиктивноеDOM
Узлы, объекты событий, фиктивные типы событий:
// 创建虚构的DOM节点
const fakeNode = document.createElement('fake');
// 创建event
const event = document.createEvent('Event');
// 创建虚构的event类型
const evtType = 'fake-event';
Инициализируйте объект события и прослушивайте события. Вызывается в обратном вызове события用户代码
. триггерное событие:
function callCallback() {
fakeNode.removeEventListener(evtType, callCallback, false);
func();
}
// 监听虚构的事件类型
fakeNode.addEventListener(evtType, callCallback, false);
// 初始化事件
event.initEvent(evtType, false, false);
// 触发事件
fakeNode.dispatchEvent(event);
Полный процесс выглядит следующим образом:
function wrapperDev(func) {
function handleWindowError(error) {
// 收集错误交给Error Boundary处理
}
function callCallback() {
fakeNode.removeEventListener(evtType, callCallback, false);
func();
}
const event = document.createEvent('Event');
const fakeNode = document.createElement('fake');
const evtType = 'fake-event';
window.addEventListener('error', handleWindowError);
fakeNode.addEventListener(evtType, callCallback, false);
event.initEvent(evtType, false, false);
fakeNode.dispatchEvent(event);
window.removeEventListener('error', handleWindowError);
}
Когда мы звоним:
wrapperDev(() => {throw Error(123)})
будет выполняться последовательно:
-
dispatchEvent
вызвать обратный вызов событияcallCallback
-
существует
callCallback
выполнить доthrow Error(123)
, выдает ошибку -
callCallback
Выполнение прерывается, но вызывающая его функция продолжает выполнение. -
Error(123)
одеялоwindow error handler
захват дляError Boundary
где шаг 2 делаетPause on exceptions
не подведет.
Шаги 3 и 4 позволяют отловить ошибку, не препятствуя последующему выполнению кода, имитируяtry catch
Эффект.
Суммировать
должен сказать,React
Эта волна операции действительно деликатная.
наша миниатюраwrapper
Есть еще много недостатков, таких как:
-
Нет совместимости для разных браузеров
-
Запущен без учета других тегов
window error handler
React
Полная версия исходного кодаwrapper
,Видетьздесь