Понимание того, почему функции обратного вызова в JavaScript выполняются только тогда, когда все заканчивается - PullRequest
1 голос
/ 21 декабря 2011

Прежде всего это то, что понимают об аргументах метода:

get(arg1, arg2) {
  arg1 + arg2
  //same as arg2 + arg1
}

Как я понимаю, не имеет значения, какой аргумент пойдет первым, результат будет таким же.

Итак, в этом примере:

 get(arg1, function(value) {
   console.log(value)
 });

Я не совсем понимаю причину, по которой второй аргумент (анонимная функция) выполняется, когда все заканчивается. Я даже не понимаю, почему он даже выполняется, если это аргумент (я понимаю, что аргументы - это просто переменные внутри функции).

По этой причине я до сих пор не могу понять обратные вызовы JavaScript (полагаю, что я путаю некоторую концепцию).

Может кто-нибудь объяснить мне это?

Ответы [ 2 ]

2 голосов
/ 21 декабря 2011

http://en.wikipedia.org/wiki/Continuation-passing_style

Я понимаю, что аргументы - это просто переменные внутри функции. То, что я хочу прояснить, это если это аргументы, которые выполняются внутри функции?

Хм, трудно сказать, что вы имеете в виду. Каким-то образом это создает впечатление, что вы считаете, что имена являются ячейками значений.

На самом деле, когда вы делаете это:

function f(y) {
    return y;
}

var x = 1;
f(x);

Тогда f (x) и имя y в пределах f относятся к одной и той же ячейке значения, ячейка которой содержит «1» (а в ячейке нет имени - имя не является ячейкой значения, и ячейка значения может иметь несколько имен, ссылающихся на него).

Что происходит со стилем передачи продолжения, так это то, что вместо этого:

function f(y, a) {
    return a * (y + 1);
}
f(y, a)

Вы также можете сделать это:

function f(y, multiplyByA) {
    return multiplyByA(y + 1);
}
f(y, function(b) { return a * b; });

Обратите внимание, как теперь вы передали функцию для использования извне. В этом случае также возможно, что f вместо немедленного вызова multiplyByA запоминает его где-то и вызывает позже.

Он также может вместо вызова передать (невостребованную) функцию кому-то еще, кто запомнит ее где-нибудь и вызовет позже, например:

function f(y, multiplyByA) {
     window.setTimeout(20, multiplyByA);
}
f(y, function(b) { return a });

Обратите внимание, что setTimeout НЕ вызывает сразу multiplyByA, а просто убирает его куда-то и возвращает вызывающему.

По прошествии времени она вызовет вашу функцию. Это не проблема, поскольку фактическая ячейка значения НЕ ограничена функцией или чем-то еще - она ​​существует столько, сколько нужно.

Это используется каждый день в Javascript - например, допустим, вы хотите что-то сделать после того, как ответ на ваш запрос XMLHttpRequest найдется. Затем вы можете создать XMLHttpRequest и установить его onreadystatechange для вашей функции. Это в конечном итоге будет называться.

Обратите внимание, что XMLHttpRequest не будет блокировать ваше приложение, пока не будет получен ответ. так вместо:

answer = XMLHttpRequest(...);
console.log(answer);

вы делаете:

XMLHttpRequest(..., function(answer) {
  console.log(answer);
});

Обратите внимание, что сразу ничего не возвращается, а ваша функция будет запомнена и будет вызвана, когда что-то произойдет.

Обратите внимание, что в Javascript функция должна быть спроектирована так, чтобы использовать стиль передачи продолжения, вы не можете просто использовать какую-либо функцию (обратите внимание, как функция f выше изменилась (!) При введении CPS).

«Не звоните нам, мы вам звоним»

2 голосов
/ 21 декабря 2011

Обратный вызов - это просто кусок кода (функция), который вы можете передать как обычные значения. Думайте об этом как о еще одном типе: числа, строки, логические значения, функции. Когда вы передаете функцию в качестве аргумента, получатель может делать с ней то, что ему нравится, и выполнять ее, когда ему нравится.

function receiver(callback) {
    callback();
}

receiver(function () {
    alert('Foo');
});

var bar = function () {
    alert('bar');
};

receiver(bar);

function baz() {
    alert('baz');
}

receiver(baz);

Приведенный выше пример bar показывает, что функции могут обрабатываться так же, как обычные значения, пример baz - это всего лишь вариант этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...