Що таке відкладені зворотні дзвінки?


15

Я розумію ідею зворотного виклику, коли я передаю функцію в іншу функцію, і ця функція використовує надану функцію за бажанням.

Я намагаюся зрозуміти відкладені зворотні дзвінки, навіть після того, як погуглити його.

Невже хтось може надати просте пояснення? Я програмую в Ruby, але також трохи знаю C / C ++, але найбільше я був досвідченим програмістом з мовної збірки. Тож мені цікаво, чи це трохи схожа на стек зворотних адрес, які отримують pop'd? Я сподіваюся дізнатися jquery або node.js, і ці відкладені зворотні виклики здаються невід’ємними для обох. Я розумію основні принципи різьблення (хоча предмет м ятеж болить голова;)


Ви маєте на увазі Deferredоб’єкти jQuery ? Це щось про специфічне для Node.js?
bfavaretto

1
Ні, я маю на увазі загалом. Хоча я хочу вивчити jquery та, можливо, node.js, я відчув, що мені потрібно зрозуміти, що саме спочатку відкладений зворотний виклик. Я читав статтю Вікіпедії про зворотні виклики, але не зміг зрозуміти відкладені зворотні виклики, які здаються властивими парадигмі асинхронної операції, яка буде задіяна в цих мовах, які її використовують.


1
Я дуже прошу концептуальної ідеї відкладеного зворотного дзвінка на відміну від їх реалізації - вибачте, якщо я не зробив цього більш зрозумілим. Я надавав мовних прикладів більше, щоб пояснити ідею, яку я намагаюся уточнити, а також моє програмування, щоб люди знали, як оцінити відповідь. Дуже дякую за відповіді досі - я туди потрапляю!
намети

Добре, я думаю, що я зараз це отримав, спасибі вам усім! Я не знаю, як би зробити відповідь. Кемерон пояснив цю концепцію найпростіше, і це було те, що я насправді шукав, але інші також звучали і додавали моїх знань. Я не впевнений, який спосіб прийняти відповідь, оскільки я новачок у цьому;)
понеділок,

Відповіді:


4

За запитом, ось коментарі, представлені як відповідь:


Я не впевнений, що ви повністю громіть на те, що функції в JS є першокласними об'єктами, і тому вони можуть зберігатися до необхідності за останній час, коли вони створені.

Наприклад, скажіть, що ви хочете записати у файл, після чого роздрукуйте повідомлення журналу; тож ви викликаєте функцію "write ()" (або будь-яку іншу) і передаєте їй функцію, яка виводить повідомлення журналу (це відкладена функція зворотного виклику). "write ()" внутрішньо зберігає посилання на дану функцію, починає писати у файл та встановлює власний зворотний дзвінок, щоб знати, коли запис закінчено. Потім він повертається до того, як буде записано; коли він є, внутрішній зворотний виклик якимось чином викликається (це основна робота основної системи - у випадку node.js це робиться з циклом подій), який потім викликає ваш зворотний дзвінок, який друкує повідомлення журналу.

"Відкладена" частина просто означає, що функція зворотного дзвінка не викликається відразу; виклик його відкладається до відповідного часу. У випадку асинхронних функцій, як у багатьох з node.js, даний зворотний виклик, як правило, викликається, коли операція завершується (або виникає помилка).

Більшість матеріалів є async у node.js, але у браузері, наприклад, jQuery, більшість матеріалів насправді є синхронним (за винятком, очевидно, для запитів AJAX). Оскільки функції першого класу настільки зручні в JavaScript (особливо через велику підтримку закриття), зворотні виклики також використовуються скрізь у браузері, але вони не "відкладені" для синхронних операцій (за винятком тих випадків, коли їх не викликають відразу ви, але пізніше за функцією, яку ви викликаєте).

Той факт, що базова система керується подіями, є ортогональним для використання відкладених зворотних викликів; ви можете уявити собі (дуже повільну) версію node.js, яка запускала потік для кожної операції, а потім викликала даний зворотний виклик, коли потік закінчив свою роботу, не використовуючи подій взагалі. Звичайно, це жахлива модель, але вона ілюструє мою думку :-)


8

Спосіб відкладеного зворотного дзвінка щоразу, коли ви додаєте до нього зворотний дзвінок, цей зворотний виклик висувається до масиву. Потім, коли .resolve()або .resolveWith()метод викликається на відкладеному об'єкті, всі.done() зворотні виклики в масиві виконуються в порядку.

Тепер ми можемо подивитися, що таке відкладений об’єкт. Візьмемо фрагмент нижче як приклад.

var deferred = $.Deferred();
var promise = deferred.promise();

Зараз у нас є відкладений об’єкт, а об'єкт - обіцянка відкладеного об'єкта. Відкладений об'єкт має всі ті ж методи, що і об'єкт обіцяє, однак об'єкт обіцянки має тільки методи .done(), .fail()і .always()які використовуються для додавання зворотних викликів до відстроченого об'єкту для кожного відповідного event. З іншого боку, відкладений об'єкт має кілька інших методів, головне .resolve()і .reject(). Коли ці методи викликаються на відкладеному об'єкті, викликаються всі зворотні виклики. .resolve()запускає .done()та .always()зворотні дзвінки, поки .reject()метод викликає .fail()і.always() відкликає виклики.

Як правило, відкладений об'єкт зберігається прихованим у приватному масштабі, а об'єкт обіцянки повертається з функції, щоб на нього можна було розмістити зворотні виклики. Відкладений об'єкт буде вирішено пізніше, наприклад, після завершення запиту ajax або після завантаження зображення, після setTimeout тощо. Важливо також усвідомити, що відкладений об'єкт може бути вирішений лише один раз. Якщо це вже вирішено, зворотні дзвінки будуть викликані негайно.

Ось ще один приклад, який я використовую:

function loadImage(url) {
    var def = $.Deferred(),
        img = new Image();
    $(img).on("load error",function(e){
        if (e.type === "error") {
            def.reject(url);
        }
        else {
            def.resolve(url);
        }
    });
    img.src = url;
    // return the promise object so that callbacks can
    // be defined on the deferred object.
    return def.promise();
}
loadImage("foobar.jpg").done(function(){
    alert("The image is loaded!");
}).fail(function(){
    alert("The image failed to load!");
}).always(function(){
    alert("This is always called!");
});

Для отримання додаткової інформації про $.Deferred()метод jQuery та відкладені об'єкти відвідайте http://api.jquery.com/category/deferred-object/


Це, ймовірно, буде неоціненним, коли я обернусь концепцією відкладеного зворотного дзвінка. Вибачте, але я все ще не розумію поняття, що таке відкладений зворотний дзвінок. Я більше шукаю концептуальної ідеї, що стоїть за нею. Сортування по ідеї Міхії. Як тільки я можу обернути голову, що, можливо, я можу зрозуміти js.
понеділок

3

Я не впевнений, але я вважаю, що відкладений зворотний виклик відноситься до асинхронного зворотного дзвінка, тож вам буде більше шансів у пошуках Google.

Найкраще пояснення, яке я знайшов, було за адресою http://www.nodebeginner.org

Гей, мабуть, ExpensiveFunction (), будь ласка, зробіть свої речі, але я, єдиний потік Node.js, не збираюсь чекати тут, поки ви закінчите, я продовжуватиму виконувати рядки коду під вами, тому, будь ласка, прийміть тут цей зворотний викликFunction () і зателефонуйте йому, коли ви закінчите робити свої дорогі речі? Спасибі!"

У цьому прикладі, ймовірноExpensiveFunction - це не блокуюча (або функція асинхронізації). Це означає, що воно виконується не відразу, а розміщується у так званому циклі подій. Потік node.js продовжить виконання, але в певний момент часу він вирішить виконати щось із циклу подій. Коли він досягає ймовірноExpensiveFunction, він викликає його, а коли ймовірноExpensiveFunction закінчує виконання, він викликає (відкладений) зворотний виклик, переданий як параметр для нього.

Як приклад, мабуть, ви можете скористатись ExpensiveFunction напевноExpensiveFunction fs.readFile


Спасибі. Але, як це буде робити дорога функція це речі, якщо вона вже повернулася, і ви знову в головній нитці виконання? Я не розумію цього. Ви кажете, що функція зберігається певним чином після її закінчення?

Відповідь відредагував, можливо, зараз зрозуміліше.

Дуже корисний. Але ... чи потрібно обробляти цей масив збережених зворотних дзвінків? Що я маю на увазі, що це обробка цього списку. Це (наприклад), що js знімає ці зворотні дзвінки у фоновому режимі, не роблячи нічого з цього приводу, чи подія викликає node.js або щось викликає певний зворотний виклик. Вибачте, я отримую приблизно 70% від того, що ви говорите, але я трохи втратив решту :)
понеділок,

@tentimes - "що це обробляє цей список" об'єкт $ .Deferred () обробляє список. Коли ви телефонуєте .resolve()або .reject()на оригінальному відкладеному об'єкті, виклик списку зворотних дзвінків .
user400654

2
@tentimes: З того, що ви говорите, я не впевнений, що ви повністю втручаєтесь у те, що функції в JS є першокласними об'єктами, і тому вони можуть зберігатися до необхідності за минулий час, коли вони створені. Наприклад, ви хочете написати у файл, а потім роздрукувати повідомлення журналу; тож ви викликаєте функцію "написати" (чи що завгодно) і передаєте їй функцію, яка виводить повідомлення журналу. "write ()" внутрішньо зберігає посилання на дану функцію, починає писати у файл та встановлює власний зворотний дзвінок, щоб знати, коли запис закінчено. Потім він повертається до того, як буде записано; коли він є, ваша функція називається.
Камерон

3

JavaScript є однопоточним, тому ви не можете думати з теми, щоб зрозуміти це. Ось приклад як регулярних, так і асинхронних зворотних викликів за допомогою jQuery:

var regularCallback = function(evt) {
    alert("I'm a callback!")
}
var asyncCallback = function(data) {
    alert("I only run when an async operation finishes!")
}

// Bind the regular callback to a button's click event
$('#mybutton').on('click', regularCallback);

// Start an ajax request to the server. The request is asynchronous, so code
// below this line will execute immediately. The callback function
// will only be called when the request is complete.
$.get("http://google.com", asyncCallback);

Тепер це мене десь заводить, дякую. Отже, асинхронний відповідає у випадку події, яку я встановив з ajax, - що просто обробляє його і якщо подія трапляється, викликається зворотний дзвінок? Я думаю, я це отримую. Чи зробить node.js / jquery щось подібне з відкладеними об’єктами jquery usnig та складною системою взаємодії з ними, щоб дійсно зробити те саме, але використовуючи методи?
понеділок

1
@tentimes, саме так! Зворотні виклики зазвичай виконуються у відповідь на події (але оскільки "зворотний виклик" не є мовою js-конструкції, іноді цей термін використовується в інших контекстах). Відкладені об'єкти (обіцянки), які ви бачите у відповіді Кевіна, - це в основному синтаксичний цукор. Вони отримуються "вирішеними" або "відхиленими", коли спрацьовує якась (асинхронна) подія, тоді вони викликають відповідний зворотний виклик ("зроблено" або "не вдалося", потім "завжди"). Використання їх у jQuery може зробити код більш читабельним та дозволяє отримати деякі додаткові хитрощі (наприклад, легке додавання другого зворотного дзвінка після запуску запиту ajax, наприклад).
bfavaretto

Обидва є асинхронними зворотними
дзвінками

1

Відкладені зворотні виклики (ака Промесис ) дозволяють писати послідовний асинхронний код, без болю і зворотних зворотів спагетті:

$.when( doAjax(), doAnotherAjax() ).then( haveFunWithMoreAjax ).then( animateStuff );

'when' дозволяє чекати паралельного повернення функцій і thenможе бути послідовно ланцюговим.

одна примітка: jQuery відкладені ! = Promices / A , їх синтаксис трохи інший.

Є хороші статті на тему: одна в IEBlog та інша у якомусь випадковому блозі , книга та популярне запитання про stackoverflow


1
е .. виявляється - ОП запитав дещо іншу річ .. ну, сподіваємось, що ця відповідь допоможе комусь іншому, колись, можливо.
c69
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.