/**
* Эта функция есть ключевая для работы всей хитрой схемы нашей асинхронности. Лазить руками не рекомендую дабы не сломать
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments)).next());
});
};
// ==UserScript==
// @name some Ajax script
// @namespace virtonomica
// @author mr_Sumkin
// @description простой шаблон скрипта с ajax запросами к серверу
// @include http*://virtonomic*.*/*/main/*
// @require https://code.jquery.com/jquery-1.11.1.min.js
// @version 1.0
// ==/UserScript==
$ = jQuery = jQuery.noConflict(true);
let $xioDebug = true;
// упрощаем себе жисть, подставляем имя скрипта всегда в лог сообщении
function log(msg, ...args) {
msg = "scriptname: " + msg; // сюда стоит вписать ваше имя скрипта
let arr = [];
arr.push(msg);
arr.push.apply(arr, args);
logDebug.apply(null, arr);
}
/**
* Главная функция скрипта. Она тоже асинхронная.
Любая функция внутри которой будет производиться асинхронный вызов, обязана быть тоже асинхронной
иначе работать как положено не будет.
*/
function run_async() {
return __awaiter(this, void 0, void 0, function* () {
log("начали");
// обычно толковый скрипт, сначала пытается что то отрисовать на странице из УЖЕ собранных данных
// а потом запрашивает новые данные по сети и обновляет страничку по мере получения этих данных
// следовательно сначала идет код отрисовки чего либо на страничке. Он обычный синхронный код
let result = someCommonCode(document);
// после выполнения стандартного обычного кода мы заводим различные запросы к серверу
// Используется особый формат вызова асинхронной функции. Он нужен для того, чтобы выполнение функции
// не продолжалось дальше, а ожидало получения данных от запроса. Как только данные будут получены,
// или произойдет ошибка запроса, функция начнет выполняться дальше.
// Если использовать обычный способ вызова без ключевого слова yield то после запуска функции
// someAsyncCode_async код начнет выполняться дальше, так как функция someAsyncCode_async асинхронная.
// Как итог будет ошибка, ведь в переменной asyncResult еще нет ничего и она undefined
let asyncResult = "";
// любой код способен давать ошибки, а асинхронный тем более, поэтому оптимально завернуть его в блок try-catch
// смысл этого куска кода - показать как легко работать с исключениями при использовании описанного здесь подхода
// к асинхронным запросам.
try {
asyncResult = yield someAsyncCode_async();
}
catch (err) {
// если наша асинхронная функция вдруг была выполнена неудачно в связи с ошибками в нашем кривом коде
// или данные не пришли от сервера, то someAsyncCode_async генерирует исключение,
// которое мы тут и ловим, а дальше просто выводим в консоль текст ошибки
// либо делаем что то что нам в голову взбредет, но лучше делать что то что позволит сразу увидеть что ошибка
// а не сидеть и гадать почему ничего не происходит
let e = err;
log(e.message);
}
// теперь зная результат запроса, мы можем обновить информацию на страничке снова используя обычную функцию
// никто не запрещает нам и этот код завернуть в try-catch но это уже на ваше усмотрение
someUpdateCode(document, asyncResult);
log("закончили");
});
}
/**
* Синхронный обычный код
* @param doc сюда можно подать документ, и дальше отработать его обычными методами jquery
*/
function someCommonCode(doc) {
// сюда можно поместить весь стандартный код для удобства.
// этот код выполнится до отправки запросов к серверу
log("someCommonCode выполнен успешно");
return "done";
}
/**
* Эта фукнция обновит страничку новыми данными
* @param doc
* @param newData новые данные которые нужно отобразить
*/
function someUpdateCode(doc, newData) {
// пишем сюда обычный синхронный код обновления данных на нашей страничке.
// все как обычно
let $html = $(doc);
$html.find("div.artf_slots").before("<b>ДАННЫЕ ПОЛУЧЕНЫ ОТ СЕРВЕРА</b>");
log("someUpdateCode выполнен успешно");
}
/**
* Некая функция с асинхронным кодом. рекомендую давать суффикс async для таких, дабы не забыть о ее асинхронности
*/
function someAsyncCode_async() {
// вот тут вся главная фишка. Внутри ЛЮБОЙ нашей асинхронной функции по факту будет будет вызыватьеся наш
// __awaiter с 4 параметрами. Первые 3 у нас стандартные и всегда такие, а вот последний являет собой функцию
// ту самую которую мы хотим создать. То есть тело любой функции которую мы хотим сделать асинхронной нужно просто завернуть
// в return __awaiter(this, void 0, void 0, function* () { "здеся будет наш код"})
// значок * после слова function указывает что это функция генератор и этот значок должен быть обязательно!!!
// ГЛАВНОЕ правило таково: если мы делаем асинхронный запрос в теле нашей функции с помощью слова yield тогда
// обязательно завернуть все тело функции в __awaiter
return __awaiter(this, void 0, void 0, function* () {
// после выполнения стандартного обычного кода мы заводим различные запросы к серверу
let url_tpl = `https://virtonomica.ru/olga/forum/forum_new/15/view`;
// Используется особый формат вызова асинхронной функции. Он нужен для того, чтобы выполнение функции
// не продолжалось дальше, а ожидало получения данных от запроса. Как только данные будут получены,
// или произойдет ошибка запроса, функция начнет выполняться дальше.
// Если использовать обычный способ вызова без ключевого слова yield то после запуска функции
// tryGet_async код начнет выполняться дальше, так как функция tryGet_async асинхронная.
// Как итог будет ошибка, ведь в переменной html еще нет ничего и она undefined
let obj = yield tryGet_async(url_tpl);
// так как функция tryGet_async возвращает объект Error в случае если запрос неудачный
// мы легко можем это обработать
if (obj instanceof Error) {
log("someAsyncCode_async выполнен c ошибкой");
throw obj; // просто выбрасываем исключение если нам проще работать с исключениями
}
// здесь уже данные точно получены, можем их парсить и насиловать как нам угодно
// НО здесь не стоит изменять исходную страницу
// смысл всей функции в получении данных а не в изменении данных на страницах сайта
let $html = $(obj);
let $tbl = $html.find("table.list");
// ...
// ...
// когда данные отработаны и все нужные величины получены, завершаем функцию и возвращаем из функции эти величины
log("someAsyncCode_async выполнен успешно");
return "async done";
});
}
// собственно сам запуск скрипта в работу
// хоть мы и вызываем асинхронную функцию, но вызываем ее как обычную, тем самым страничка
// на которой запускается данный скрипт не замораживается на время ожидания ответов от запросов к серверу
$(document).ready(() => run_async());
//
// Набор штатных функций для стандартной обработки запросов
//
/**
* Запрашивает страницу. При ошибке поробует повторить запрос через заданное число секунд.
* Пробует заданное число попыток, после чего возвращает reject.
* При ресолве вернет текст страницы, а при реджекте вернет Error объект
* @param url
* @param retries число попыток загрузки
* @param timeout таймаут между попытками
*/
function tryGet_async(url, retries = 10, timeout = 1000) {
return __awaiter(this, void 0, void 0, function* () {
let $deffered = $.Deferred();
$.ajax({
url: url,
type: "GET",
success: (data, status, jqXHR) => $deffered.resolve(data),
error: function (jqXHR, textStatus, errorThrown) {
retries--;
if (retries <= 0) {
let err = new Error(`can't get ${this.url}\nstatus: ${jqXHR.status}\ntextStatus: ${jqXHR.statusText}\nerror: ${errorThrown}`);
$deffered.reject(err);
return;
}
let _this = this;
setTimeout(() => { $.ajax(_this); }, timeout);
}
});
return $deffered.promise();
});
}
/**
* Берет строку JSON и конвертает поля в данные. Числа в числа, null в нулл, и t/f в true/false
* @param jsonStr
*/
function parseJSON(jsonStr) {
let obj = JSON.parse(jsonStr, (k, v) => {
if (v === "t")
return true;
if (v === "f")
return false;
return (typeof v === "object" || isNaN(v)) ? v : parseFloat(v);
});
return obj;
}
/**
* Аналогично обычному методу tryGet_async правда возвращает json объект
и конвертает по ходу дела числа в числа если они идут строкой
*/
function tryGetJSON_async(url, retries = 10, timeout = 1000) {
return __awaiter(this, void 0, void 0, function* () {
let $deffered = $.Deferred();
$.ajax({
url: url,
type: "GET",
cache: false,
dataType: "text",
success: (jsonStr, status, jqXHR) => {
let obj = parseJSON(jsonStr);
$deffered.resolve(obj);
},
error: function (jqXHR, textStatus, errorThrown) {
retries--;
if (retries <= 0) {
let err = new Error(`can't get ${this.url}\nstatus: ${jqXHR.status}\ntextStatus: ${jqXHR.statusText}\nerror: ${errorThrown}`);
$deffered.reject(err);
return;
}
let _this = this;
setTimeout(() => { $.ajax(_this); }, timeout);
}
});
return $deffered.promise();
});
}
function logDebug(msg, ...args) {
if (!$xioDebug)
return;
console.log(msg, ...args);
}
Add a code snippet to your website: www.paste.org