Я зациклен на делегатах и замыканиях в JavaScript, и мне кажется, что я столкнулся с ситуацией, в которой я хотел бы попытаться использовать один или оба.
У меня есть веб-приложение, которое во многом похоже на приложение форм, с полями, обращающимися к серверу для изменения данных в каждом onBlur или onChange (в зависимости от элемента формы). Я использую веб-службы ASP.NET 3.5 и jQuery для выполнения большей части работы.
Что нужно знать для примера:
isBlocking()
- это простой механизм для синхронизации некоторых функций (например, мьютекса)
isDirty(el)
проверяет, что значение элемента действительно изменилось, прежде чем тратить вызов на сервер
Agent()
возвращает одноэлементный экземпляр прокси-класса WebService
getApplicationState()
передает строку в кодировке base-64 в веб-службу. Эта строка представляет состояние приложения - значение элемента и состояние передаются службе, которая выполняет некоторые вычисления. Функция onSuccess вызова веб-службы возвращает новое состояние, которое клиент обрабатывает и обновляет весь экран.
waitForCallback()
устанавливает флаг, который isBlocking()
проверяет мьютекс
Вот пример одной из 50 очень похожих функций:
function Field1_Changed(el) {
if (isBlocking()) return false;
if (isDirty(el)) {
Agent().Field1_Changed($j(el).val(), getApplicationState());
waitForCallback();
}
}
Большая проблема в том, что методы Agent().Field_X_Changed
могут принимать различное количество параметров, но обычно это просто значение и состояние. Таким образом, написание этих функций становится повторяющимся. Я сделал это до сих пор, чтобы попробовать с помощью делегатов:
function Field_Changed(el, updateFunction, checkForDirty) {
if (isBlocking()) return false;
var isDirty = true; // assume true
if (checkForDirty === true) {
isDirty = IsDirty(el);
}
if (isDirty) {
updateFunction(el);
waitForCallback();
}
}
function Field1_Changed(el) {
Field_Changed(el, function(el) {
Agent().Field1_Changed($j(el).val(), getTransactionState());
}, true);
}
Это нормально, но иногда у меня может быть много параметров:
...
Agent().Field2_Changed($j(el).val(), index, count, getApplicationState());
....
В конечном итоге я хотел бы сделать звонки одним бельем, что-то вроде этого (обратите внимание, getTransactionState()
звонки - я бы хотел как-то автоматизировать это):
// Typical case: 1 value parameter
function Field1_Changed(el) {
Field_Changed(el, delegate(Agent().Field1_Changed, $j(el).val()), true);
}
// Rare case: multiple value parameters
function Field2_Changed(el, index, count) {
Field_Changed(el, delegate(Agent().Field1_Changed, $j(el).val(), index, count), true);
}
function Field_Changed(el, theDelegate, checkIsDirty) {
???
}
function delegate(method) {
/* create the change delegate */
???
}
Хорошо, мой первый вопрос: стоит ли это того? Это труднее читать, но легче поддерживать или наоборот? Это довольно хорошее мероприятие, поэтому я могу в конечном итоге назначить награду за это, но я был бы признателен за любую помощь, которую вы могли бы предложить. Спасибо!
UPDATE
Итак, я принял ответ, основываясь на том факте, что он указал мне правильное направление. Я подумал, что вернусь и опубликую свое решение, чтобы у других, кто только начинает с делегатами, было что-то для моделирования. Я также публикую его, чтобы узнать, хочет ли кто-нибудь попробовать его оптимизировать или внести предложения. Вот общий метод Field_Changed()
, который я придумал, с checkForDirty
и omitState
необязательными параметрами:
function Field_Changed(el, args, delegate, checkForDirty, omitState) {
if (isBlocking()) return false;
if (!$j.isArray(args) || args.length == 0) {
alert('The "args" parameter in Field_Changed() must be an array.');
return false;
}
checkForDirty = checkForDirty || true; // assume true if not passed
var isDirty = true; // assume true for updates that don't require this check
if (checkForDirty === true) {
isDirty = fieldIsDirty(el);
}
if (isDirty) {
omitState = omitState || false; // assume false if not passed
if (!omitState) {
var state = getTransactionState();
args.push(state);
}
delegate.apply(this, args);
waitForCallback();
}
}
Он обрабатывает все, что мне нужно (проверка на грязность, применение состояния приложения, когда оно мне нужно, и принудительное выполнение синхронных вызовов веб-службы. Я использую его так:
function TransactionAmount_Changed(el) {
Field_Changed(el, [cleanDigits($j(el).val())], Agent().TransactionAmount_Changed, true);
}
cleanDigits
удаляет ненужные символы, которые пользователь, возможно, пытался набрать. Так что, спасибо всем, и счастливого кодирования!