Лекция 8 �AJAX, фоновые задачи
intervolga.ru/school/
Никита Владимирович Калинин,
ИНТЕРВОЛГА
Устройство ИНТЕРНЕТА,
HTTP, HTML, верстка
Веб-сервер�Лекции 1 и 2�ЛР 1
Работа с данными�PHP, MySQL, веб-формы, фильтрация данных�Лекции 3 и 4�ЛР 2
Работа с формами, куками, сессиями.
Авторизация, регистрация, проверка доступа�Лекции 5 и 6�ЛР 3
Обработка текста на PHP.
Организация длительных операций и точек доступа для AJAX�Лекции 7 и 8�ЛР 4
GET/POST URL
HTML
Программа на сервере (сайт):
HTTP
Веб-часть
Браузер
GET/POST URL
HTML
GET/POST URL
HTML
Программа на сервере (сайт):
HTTP
Веб-часть
Браузер
AJAX
GET/POST URL
HTML
GET/POST URL
HTML
Фоновые задачи
Программа на сервере (сайт):
HTTP
Веб-часть
Браузер
AJAX
Технология AJAX
HTTP-запросы из JavaScript
HTTP-запросы из JavaScript
Синхронное выполнение кода
function a() {
b()
c()
}
t
a()
b()
c()
Синхронное выполнение кода
Асинхронное выполнение кода
function a() {
b()
c()
}
function a() {
b()
c()
}
t
a()
b()
c()
t
a()
b()
c()
Как возвращать значение?
Асинхронный JavaScript: функции обратного вызова
function a(callback) {
b(resB => {
c(resC => {
let resA = resB + resC
callback(resA)
})
})
}
// Вызов асинхронной функции
a(res => {
console.log(res)
})
function (arg) {
...
}
arg => {
...
}
==
Асинхронный JavaScript: Promise
function a() {
let resB
return b().then(res => {
resB = res
return c()
}).then(resC => {
return resB + resC
})
}
// Вызов асинхронной функции
a().then(res => {
console.log(res)
})
Асинхронный JavaScript: async/await
async function a() {
let resB = await b()
let resC = await c()
return resB + resC
}
// Вызов асинхронной функции
let res = await a()
// Вызов a() из синхронной функции
a().then(res => {
console.log(res)
})
Разберемся в терминах: что такое concurrency?
Один поток
Многопоточность
Блокирующие вызовы
Неблокирующие вызовы
Разберемся в терминах: что такое concurrency?
Один поток
Многопоточность
Блокирующие вызовы
Неблокирующие вызовы
Язык не позволяет выполнять несколько задач одновременно
Разберемся в терминах: что такое concurrency?
Один поток
Многопоточность
Блокирующие вызовы
Неблокирующие вызовы
Язык не позволяет выполнять несколько задач одновременно
Кооперативная многозадачность (в один момент времени выполняется только одна задача)
Разберемся в терминах: что такое concurrency?
Один поток
Многопоточность
Блокирующие вызовы
Неблокирующие вызовы
Язык не позволяет выполнять несколько задач одновременно
Кооперативная многозадачность (в один момент времени выполняется только одна задача)
Вытесняющая многозадачность и/или параллелизм, ресурсоемкий, сложный подход
Разберемся в терминах: что такое concurrency?
Один поток
Многопоточность
Блокирующие вызовы
Неблокирующие вызовы
Язык не позволяет выполнять несколько задач одновременно
Кооперативная многозадачность (в один момент времени выполняется только одна задача)
Вытесняющая многозадачность и/или параллелизм, ресурсоемкий, сложный подход
Вытесняющая многозадачность и/или параллелизм, эффективный, очень сложный подход
Разберемся в терминах: что такое concurrency?
Один поток
Многопоточность
Блокирующие вызовы
Неблокирующие вызовы
Язык не позволяет выполнять несколько задач одновременно
Кооперативная многозадачность (в один момент времени выполняется только одна задача)
Вытесняющая многозадачность и/или параллелизм, ресурсоемкий, сложный подход
Вытесняющая многозадачность и/или параллелизм, эффективный, очень сложный подход
PHP
JavaScript
Go
C#
Java
HTTP-запросы из JavaScript
let resp = await fetch('/some/url/')
let body = await resp.json()
console.log(body)
GET
let resp = await fetch('/some/url/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
})
let body = await resp.json()
console.log(body)
POST с заголовками
Пример: форма входа на AJAX
<form id="signIn">
<div class="errors"></div>
Логин:
<input name="login">
Пароль:
<input name="passwd" type="password">
<button>Войти</button>
</form>
<script>
</script>
let form = document.querySelector('#signIn')
form.onsubmit = e => {
// Обработка...
// Чтобы браузер не сделал обычную
// отправку формы.
return false
}
Пример: форма входа на AJAX
<form id="signIn">
<div class="errors"></div>
Логин:
<input name="login">
Пароль:
<input name="passwd" type="password">
<button>Войти</button>
</form>
<script>
</script>
let form = document.querySelector('#signIn')
form.onsubmit = async e => {
let resp = await fetch('/api/login/', {
method: 'POST',
body: form,
})
if (resp.status == 200) {
window.location.href = '/personal/'
return false
}
let err = await resp.text()
let errDiv = form.querySelector('.errors')
errDiv.textContent = err
return false
}
Чего не хватает?
Пример: форма входа на AJAX
<?php
$root = $_SERVER['DOCUMENT_ROOT'];
require_once "{$root}/core/index.php";
$login = $_POST['login'];
$passwd = $_POST['passwd'];
$err = UserLogic::signIn($login, $passwd);
if ($err) {
// Статус ответа: 403 Bad Request.
http_response_code(403);
echo $err;
die;
}
// Статус ответа: 204 No Content
// (у ответа нет тела).
http_response_code(204);
Фоновые задачи
Фоновые задачи
Примеры фоновых задач:
Консольные PHP-скрипты
#!/usr/bin/env php
<?php
echo "Hello\n\n";
user@host:~$ php -f script.php
Hello
user@host:~$ ./script.php
Hello
Запуск консольных скриптов
Планировщик cron
user@host:~$ crontab -e -u <польз.>
Конфигурация планировщика cron
* * * * * php -f script1.php
15 2 * * * php -f script2.php
*/10 * * * * php -f script3.php
0 0 1 * * php -f script4.php
0 6,15 * * sun php -f script5.php
Минуты
Часы
Дни
Месяцы
Дни недели
Команда
Пустая строка в конце обязательна!
Иначе последняя команда не будет запускаться.
Собственный планировщик «на хитах»
Собственный планировщик «на хитах»
Завести таблицу (аналог конфигурации cron), в которой хранить:
id | lastRun | interval | ... |
task1 | 01.01.2022 17:41:19 | 60 | |
task2 | 01.01.1970 00:00:00 | 300 | |
... |
Особенности планировщика «на хитах»
Длительные задачи
Выполнение длительных задач
Примеры задач:
Два способа выполнения длительных задач:
НЕ фоновое выполнение длительных задач
<?php
const path = 'upload/big.csv';
const max = 1000;
$pos = (int) ($_GET['pos'] ?? 0);
$f = fopen(path, 'r');
fseek($pos);
$cnt = 0;
while ($cnt < max && $row = fgetcsv($f)) {
// Обработать строку $row...
$cnt++;
}
$pos = ftell($f);
$finished = feof($f);
fclose($f);
if (!$finished) {
header("Location: import.php?pos={$pos}");
}
echo 'Готово.';
НЕ фоновое выполнение длительных задач
Ограничения:
Совет:
«Не в фоне» можно выполнять только задачи, которые будут запускать программисты или администраторы — технически грамотные лица.
Фоновое выполнение длительных задач
Если задачу нужно запускать через равные периоды времени:
Если задачу надо запускать по требованию:
Очередь задач
С точки зрения брокера есть два действующих лица:
Сообщение может описывать задачу, которую нужно выполнить.
Характеристики брокеров сообщений