Использование thunk для выделения времени из асинхронного кода
У Кайла Симпсона потрясающий класс по множеству мнений.
В одном из модулей он просматривает фрагмент кода, который можно безопасно вызывать асинхронно, и быть уверенным, что результаты будут показаны пользователю в той же последовательности, в которой был выполнен код.
Функция во всей красе:
function getFile(file) {
var text, fn;
fakeAjax(file, function(response){
if (fn) fn(response);
else text = response;
});
return function(cb) {
if (text) cb(text);
else fn = cb;
}
}
Мы можем назвать это так:
Мне трудно понять функцию getFile:
- где определяется cb? как это называется, то есть
cb(text)
если это нигде не определено? - когда мы вызываем getFile, как
response
получить значение вообще?
1 ответ
getFile
возвращает анонимную функцию:
return function(cb) {
if (text) cb(text);
else fn = cb;
}
так var th1 = getFile("file")
заканчивает тем, что присваивает эту анонимную функцию значению th1
, так th1
теперь можно вызывать с аргументом - который становится cb
, Поэтому, когда позже мы позвоним th1
с:
th1(function(text1) {
...
мы передаем вторую анонимную функцию (с аргументом text1), которая назначается cb
(сокращение для "обратного вызова").
Причина, по которой он работает, заключается в том, что когда AJAX завершен, он выполняет одно из двух:
- если
fn
определяется, звонкиfn
с ответом - если нет, то хранит ответ
И наоборот, когда вызывается возвращенная анонимная функция, она выполняет одно из двух:
- если
text
определяется (т. е. результат уже получен), затем он вызывает обратный вызов с ответом - если нет, он назначает обратный вызов (
cb
) чтобыfn
Таким образом, в зависимости от того, что произойдет первым - ajax complete или thunk вызывается, состояние сохраняется, а затем, в зависимости от того, что происходит вторым, выполняется результат.
Таким образом, 'thunks' могут быть объединены в цепочку, чтобы гарантировать, что в то время как функции ajax происходят параллельно, методы вывода вызываются только в той последовательности, в которой fn
значения назначены.
Я думаю, что часть путаницы заключается в неясном присвоении имен переменным и использовании либеральных анонимных функций, не давая им намерения раскрыть имя. Следующее должно быть функционально эквивалентно с более ясным именованием (я думаю):
function getFile(file) {
var _response, _callback;
fakeAjax(file, function(response){
if (_callback) _callback(response);
else _response = response;
});
var onComplete = function(callback) {
if (_response) callback(_response);
else _callback = callback;
}
return onComplete;
}
затем:
var onFile1Complete = getFile("file1");
var onFile2Complete = getFile("file2");
var onFile3Complete = getFile("file3");
var file3Completed = function(file3Response) {
output("file3Response");
output("Complete!");
}
var file2Completed = function(file2Response) {
output(file2Response);
onfile3Complete(file3Completed)
}
var file1Completed = function(file1Response) {
output(file1Response);
onFile2Complete(file2Completed);
}
onFile1Complete(file1Completed);