Как правильно размещать JavaScript код в HTML документе

Вопрос о размещении JS скриптов в HTML

У меня есть два вопроса по поводу того, где лучше всего размещать JavaScript код в HTML документе. Не могу разобраться с парой моментов.

Первый вопрос

Если я размещу скрипт в секции <head>, и этот скрипт будет пытаться найти HTML элемент по его ID и добавить обработчик события клика, будет ли это работать? Ведь HTML содержимое еще не загрузилось на момент выполнения скрипта.

// Пример кода в head
function setupButtonHandler() {
    const myButton = document.getElementById('submitBtn');
    myButton.addEventListener('click', handleButtonClick);
}

function handleButtonClick() {
    console.log('Кнопка была нажата!');
}

Второй вопрос

С другой стороны, если я зарегистрирую функцию в head, которая вызывается после загрузки DOM, и внутри этой функции размещу код для регистрации обработчика клика по кнопке, то получается что пользователь может успеть нажать на кнопку до того, как обработчик будет зарегистрирован?

document.addEventListener('DOMContentLoaded', function() {
    const actionButton = document.getElementById('actionBtn');
    actionButton.onclick = processButtonClick;
});

function processButtonClick() {
    alert('Обработчик сработал!');
}

Какой самый правильный способ размещения JavaScript в HTML с учетом этих двух моментов?

Недавно у меня была такая же проблема! Async и defer работают только с внешними файлами - для инлайн скриптов они бесполезны. Оберни код в IIFE и проверяй document.readyState. Если уже complete - выполняй сразу, если нет - вешай на DOMContentLoaded. У меня работает стабильно даже на медленном интернете, где пользователи успевают понакликать.

Первый вопрос - да, не работает, если элемент еще не создан. Второй - теоретически пользователь может кликнуть, но это почти нереально, DOMContentLoaded срабатывает мгновенно. Самый надежный способ - ставить скрипты перед . DOM уже построен, можно сразу обращаться к элементам без всяких DOMContentLoaded listener’ов. Делаю так 8 лет, проблем не было.

Я ставлю скрипты в конец body, но есть крутой трюк - добавь defer к тегу script. Тогда скрипт запустится только после загрузки DOM, даже из head. Как встроенный DOMContentLoaded. Супер для внешних библиотек - они грузятся вместе с HTML, но выполняются по порядку.