В старых браузерах для взамодействия с сервером небходимо было использовать XMLHttpRequest и обработку событий load после загрузки ресурса с сервера, в результате код превращался в так называемый [ад колбэков](https://learn.javascript.ru/callbacks).
В современном JavaScript для упрощения обработки используются [Promise](http://learn.javascript.ru/promise-basics).
Конструктору Promise передается функция с двумя аргументами, которые тоже являются функциями. Первая функция вызывается при успешном завершении действия, вторая - при ошибке.
Далее к Promise можем присоединять действия, которые будут выполняться с результатом в случае успеха (метод then) или неудачи (метод catch). В результате получается цепочка из Promise, конвейер.
```run-html
<html>
<head></head>
<body>
<pre><code class="lang-js">
let x='abc';
</code></pre>
<div id="message"><div>
<script>
function showMessage(t) { message.innerText=t; }
function loadScript(src) {
return new Promise(function(resolve, reject) {
let script = document.createElement('script');
script.src = src;
script.onload = () => resolve(script);
script.onerror = () => reject(`Ошибка загрузки скрипта ${src}`);
document.head.append(script);
});
}
function loadLink(href, rel) {
return new Promise(function(resolve, reject) {
let link = document.createElement('link');
link.href = href;
link.rel = rel;
link.onload = () => resolve(link);
link.onerror = () => reject(`Ошибка загрузки ресурса ${href}`);
document.head.append(link);
});
}
try {
if(document.querySelector('pre code')!==null) { // Загружаем модули только при необходимости
loadLink("//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.10/styles/default.min.css","stylesheet")
.then(r => loadScript("//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.10/highlight.min.js"), showMessage)
.then(r => { hljs.initHighlightingOnLoad(); }, showMessage);
}
else
showMessage('Не загружаем!');
}
catch(err) {
showMessage('Error: '+err.message);
}
</script>
</html>
```
Попробуйте подставить другие варианты:
```javascript
// Вариант с ошибкой - не ждем окончания загрузки
loadLink("//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.10/styles/default.min.css","stylesheet");
loadScript("//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.10/highlight.min.js");
hljs.initHighlightingOnLoad();
// Загружаем последовательно, вариант 2
[
r => loadLink("//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.10/styles/default.min.css","stylesheet"),
r => loadScript("//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.10/highlight.min.js"),
r => { hljs.initHighlightingOnLoad(); }
].reduce((p, f) => p.then(f, showMessage), Promise.resolve());
async ставится перед функцией, гарантируя, что она вернет Promise.
```run-js
async function f() {
return 'готово';
}
f().then(console.log);
```
await ставится перед Promise, заставляя интерпретатор ждать завершения выполнения (на самом деле async заставляет переделать код функции в цепочку вызовов Promise и интерпретатор не ждет!).
```run-js
// умножаем x на 2 в течении 2 секунд (очень сложные вычисления!)
function returnAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => resolve(x*2), 2000);
});
}
async function add(x,y) {
const a = await returnAfter2Seconds(x);
const b = await returnAfter2Seconds(y);
return a + b;
}
console.log('Ответ будет через 4 секунды');
add(10,20).then(console.log);
console.log('А пока можем делать что-то другое');
```
В функциональном прграммировании есть аналог - ленивые вычисления (delay/force).
fetch
fetch возвращает Promise, отправляющий запрос на ресурс на сервер.
```javascript
let promise = fetch(URL, опции);
```
По умолчанию отпраляется GET-запрос, для отправки POST-запроса в формате JSON нужно написать: