-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
157 lines (136 loc) · 5.13 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
startMysteriousProcess('https://keev.me/f/slowpoke.php')
/**
* Рендерит черный квадрат;
* спустя задержку анимирует квадрат и посылает запрос;
* после анимации и получения ответа, меняет цвет квадрата.
*
* @param url - ендпоинт запроса
* @param delay - задержка до начала анимации и запроса
*/
function startMysteriousProcess(url, delay = 1000) {
warn('function started')
if (!isUrlValid(url)) {
throw new Error()
}
const square = document.createElement('div')
renderSquare(square)
warn('square rendered')
setTimeout(async () => {
// Promise.all гарантирует, что дальнейший код (смена цвета квадрата) исполнится
// только после того, как закончится анимация и будет получен ответ от сервера
const [_, apiResponse] = await Promise.all([
animateSquare(square),
getUrlData(url)
])
changeSquareColor(square, apiResponse)
warn('square painted with apiResponse: ' + apiResponse)
}, delay)
/********************************
* Служебные функции и константы
********************************/
/** Используется для индикации состояния ответа сервера.
* @type {{readonly SUCCESS: number, _SUCCESS: number, _ERROR: number, readonly ERROR: number, _FAILURE: number, readonly FAILURE: number}}
*/
const RESPONSE_STATE = {
// мы не хотим, чтобы кто-то менял свойства этого объекта - эмулируем защищенные свойства
_FAILURE: 0,
_SUCCESS: 1,
_ERROR: -1,
get FAILURE() { return this._FAILURE },
get SUCCESS() { return this._SUCCESS },
get ERROR() { return this._ERROR }
}
/**
* Простая проверка валидности url.
* @param url
* @returns {boolean}
*/
function isUrlValid(url) {
return /^(http|https):\/\/[^ "]+$/.test(url)
}
/**
* Задаем свойства квадрата и добавляем его в DOM.
* @param square - DOM элемент
*/
function renderSquare(square) {
// позиционируем абсолютно, тем самым избегаем reflow при анимации
square.style.position = 'absolute'
// кроме отсутствия reflow абсолютное позиционирование позволяет нам
// расположить квадрат точно в левом верхнем углу вне зависимости от дефолтных стилей браузера
square.style.left = '0'
square.style.top = '0'
square.style.height = '100px'
square.style.width = '100px'
square.style.backgroundColor = 'black'
document.body.prepend(square)
}
/**
* Анимирует движение квадрата слева направо.
* @param square - DOM элемент
* @param duration - продолжительность анимации
* @param distanceX - смещение
* @returns {Promise<Animation>}
*/
function animateSquare(square, duration = 1000, distanceX = '100px') {
const {finished} = square.animate([
{ transform: 'translate3D(0, 0, 0)' },
{ transform: `translate3D(${distanceX}, 0, 0)` }
], {
fill: "forwards",
duration,
})
warn('animation started')
// Промис finished разрешиться, когда анимация закончится
return finished.then(p => {
warn('animation finished')
return p
})
}
/**
* Посылает запрос на сервер и возвращает одно из значений RESPONSE_STATE.
* @param url
* @returns {Promise<Response>}
*/
function getUrlData(url) {
warn('request send')
return fetch(url)
.then(res => {
warn('response got')
if (res.status !== 200) {
return Promise.resolve(RESPONSE_STATE.ERROR)
}
return res.json()
})
.catch(() => {
warn('network error')
return Promise.resolve(RESPONSE_STATE.ERROR)
})
}
/**
* Изменяет цвет квадрата в зависимости от responseState.
* @param square - DOM Элемент
* @param responseState - Код ответа сервера
*/
function changeSquareColor(square, responseState) {
switch (responseState) {
case RESPONSE_STATE.SUCCESS:
square.style.backgroundColor = 'green'
break
case RESPONSE_STATE.FAILURE:
square.style.backgroundColor = 'blue'
break
case RESPONSE_STATE.ERROR:
square.style.backgroundColor = 'red'
break
default:
throw Error('Unknown response')
}
}
/**
* Отмечает в консоли сообщения с моментом времени.
* @param message
*/
function warn(message) {
console.warn(`${message} at:`, performance.now())
}
}