В различных образцах javascript, которые Google предоставляет для своего API (например, здесь), они используют следующий код для загрузки скрипта из html:
<script async defer src="https://apis.google.com/js/api.js"
onload="this.onload=function(){};handleClientLoad()"
onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>
Я понимаю, что async/defer
сообщает браузеру, когда загружать и исполнять скрипт и несколько противоречить друг другу. У меня мало вопросов:
async
и defer
в этом контексте?onload
, почему они сначала назначают пустую функцию (function(){};
) событию перед вызовом handleClientLoad()
?Благодарю.
Это довольно хорошо освещено в стандарте WHAT-WG для HTML-раздела, посвященного async
и defer
, который включает эту удобную графику:
1. В чем смысл использования async и отсрочки в этом контексте?
Если браузер поддерживает async
, он игнорирует defer
и работает async. Если нет, но он поддерживает defer
, вместо этого происходит отсрочка. Если это не поддерживает, скрипт блокирует разбор DOM, но все современные браузеры поддерживают хотя бы один.
2. Почему Google решил использовать эту технику? Имеет ли он какие-либо результаты или другие преимущества?
async
извлекает сценарий, не блокируя разбор и рендеринг DOM, и запускает его, как только он доступен, даже если разбор и рендеринг DOM все еще продолжается. defer
также избегает блокировки разбора и рендеринга DOM, но не запускает скрипт до тех пор, пока синтаксический анализ не будет завершен (например, потенциально позже).
3. В событии onload, почему они сначала назначают пустую функцию (
function(){};
) событию перед вызовомhandleClientLoad()
?
Это становится ясно, если посмотреть на onreadystatechanged
: В основном это гарантирует, что handleClientLoad
вызывается только один раз GAPI, потенциально не дважды (один раз onload
и один раз onreadystatechanged
.)
4. Если я хочу переместить весь javascript в отдельный файл js, какой лучший подход для загрузки обоих скриптов? Поскольку новый js файл будет зависеть от api.js и не может быть загружен асинхронно?
Ну, он может быть загружен асинхронно, вам просто нужно обработать условие гонки с помощью api.js
Я бы наверное:
Имеет handleClientLoad
в встроенном скрипте над тегом script
загружающим api.js
, примерно так:
var clientLoaded = false;
function handleClientLoad() {
if (!clientLoaded &&
typeof mainScriptLoad !== "undefined" &&
typeof gapi !== "undefined") {
clientLoaded = true;
mainScriptLoad();
}
}
Имейте mainScriptLoad
в отдельный файл.
В конце вашего отдельного файла вызовите handleClientLoad
.
Сюда:
handleClientLoad
но handleClientLoad
увидит, что GAPI еще не загружен и ничего не сделает; позже, когда GAPI загрузится, он вызовет handleClientLoad
и вызовет mainScriptLoad
потому что все готово.handleClientLoad
но handleClientLoad
увидит, что ваш основной скрипт еще не загружен и не пытается его вызвать. Позже, когда ваш скрипт загружается и вызывает handleClientLoad
, handleClientLoad
вызовет mainScriptLoad
потому что все готово.
onload
иonreadystatechange
? Для поддержки разных браузеров?