/**
* Эта функция есть ключевая для работы всей хитрой схемы нашей асинхронности. Лазить руками не рекомендую дабы не сломать
*/// ==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==
// упрощаем себе жисть, подставляем имя скрипта всегда в лог сообщении
"scriptname: " + msg; // сюда стоит вписать ваше имя скрипта
/**
* Главная функция скрипта. Она тоже асинхронная.
Любая функция внутри которой будет производиться асинхронный вызов, обязана быть тоже асинхронной
иначе работать как положено не будет.
*/"начали");
// обычно толковый скрипт, сначала пытается что то отрисовать на странице из УЖЕ собранных данных
// а потом запрашивает новые данные по сети и обновляет страничку по мере получения этих данных
// следовательно сначала идет код отрисовки чего либо на страничке. Он обычный синхронный код
// после выполнения стандартного обычного кода мы заводим различные запросы к серверу
// Используется особый формат вызова асинхронной функции. Он нужен для того, чтобы выполнение функции
// не продолжалось дальше, а ожидало получения данных от запроса. Как только данные будут получены,
// или произойдет ошибка запроса, функция начнет выполняться дальше.
// Если использовать обычный способ вызова без ключевого слова yield то после запуска функции
// someAsyncCode_async код начнет выполняться дальше, так как функция someAsyncCode_async асинхронная.
// Как итог будет ошибка, ведь в переменной asyncResult еще нет ничего и она undefined
"";
// любой код способен давать ошибки, а асинхронный тем более, поэтому оптимально завернуть его в блок try-catch
// смысл этого куска кода - показать как легко работать с исключениями при использовании описанного здесь подхода
// к асинхронным запросам.
// если наша асинхронная функция вдруг была выполнена неудачно в связи с ошибками в нашем кривом коде
// или данные не пришли от сервера, то someAsyncCode_async генерирует исключение,
// которое мы тут и ловим, а дальше просто выводим в консоль текст ошибки
// либо делаем что то что нам в голову взбредет, но лучше делать что то что позволит сразу увидеть что ошибка
// а не сидеть и гадать почему ничего не происходит
let e = err;
log(e.message);
}
// теперь зная результат запроса, мы можем обновить информацию на страничке снова используя обычную функцию
// никто не запрещает нам и этот код завернуть в try-catch но это уже на ваше усмотрение
"закончили");
});
}
/**
* Синхронный обычный код
* @param doc сюда можно подать документ, и дальше отработать его обычными методами jquery
*/// сюда можно поместить весь стандартный код для удобства.
// этот код выполнится до отправки запросов к серверу
log("someCommonCode выполнен успешно""done";
}
/**
* Эта фукнция обновит страничку новыми данными
* @param doc
* @param newData новые данные которые нужно отобразить
*/// пишем сюда обычный синхронный код обновления данных на нашей страничке.
// все как обычно
"div.artf_slots""<b>ДАННЫЕ ПОЛУЧЕНЫ ОТ СЕРВЕРА</b>");
log("someUpdateCode выполнен успешно");
}
/**
* Некая функция с асинхронным кодом. рекомендую давать суффикс async для таких, дабы не забыть о ее асинхронности
*/// вот тут вся главная фишка. Внутри ЛЮБОЙ нашей асинхронной функции по факту будет будет вызыватьеся наш
// __awaiter с 4 параметрами. Первые 3 у нас стандартные и всегда такие, а вот последний являет собой функцию
// ту самую которую мы хотим создать. То есть тело любой функции которую мы хотим сделать асинхронной нужно просто завернуть
// в return __awaiter(this, void 0, void 0, function* () { "здеся будет наш код"})
// значок * после слова function указывает что это функция генератор и этот значок должен быть обязательно!!!
// ГЛАВНОЕ правило таково: если мы делаем асинхронный запрос в теле нашей функции с помощью слова yield тогда
// обязательно завернуть все тело функции в __awaiter
// после выполнения стандартного обычного кода мы заводим различные запросы к серверу
let url_tpl = `https://virtonomica.ru/olga/forum/forum_new/15/view`;
// Используется особый формат вызова асинхронной функции. Он нужен для того, чтобы выполнение функции
// не продолжалось дальше, а ожидало получения данных от запроса. Как только данные будут получены,
// или произойдет ошибка запроса, функция начнет выполняться дальше.
// Если использовать обычный способ вызова без ключевого слова yield то после запуска функции
// tryGet_async код начнет выполняться дальше, так как функция tryGet_async асинхронная.
// Как итог будет ошибка, ведь в переменной html еще нет ничего и она undefined
// так как функция tryGet_async возвращает объект Error в случае если запрос неудачный
// мы легко можем это обработать
"someAsyncCode_async выполнен c ошибкой"// просто выбрасываем исключение если нам проще работать с исключениями
}
// здесь уже данные точно получены, можем их парсить и насиловать как нам угодно
// НО здесь не стоит изменять исходную страницу
// смысл всей функции в получении данных а не в изменении данных на страницах сайта
"table.list");
// ...
// ...
// когда данные отработаны и все нужные величины получены, завершаем функцию и возвращаем из функции эти величины
log("someAsyncCode_async выполнен успешно""async done";
});
}
// собственно сам запуск скрипта в работу
// хоть мы и вызываем асинхронную функцию, но вызываем ее как обычную, тем самым страничка
// на которой запускается данный скрипт не замораживается на время ожидания ответов от запросов к серверу
//
// Набор штатных функций для стандартной обработки запросов
//
/**
* Запрашивает страницу. При ошибке поробует повторить запрос через заданное число секунд.
* Пробует заданное число попыток, после чего возвращает reject.
* При ресолве вернет текст страницы, а при реджекте вернет Error объект
* @param url
* @param retries число попыток загрузки
* @param timeout таймаут между попытками
*/"GET"'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'