Асинхронное программирование в javascript (обратные вызовы)

Обратный вызов — это функция, которую вы пишете и затем передаете другой функции. Затем эта функция вызывает вашу функцию, когда выполняется какое-то условие или происходит какое-то событие. Вызов предоставленной вами функции обратного вызова уведомляет вас об условии или событии, а иногда в вызов включаются аргументы функции, которые предоставляют дополнительные сведения.

Это легче понять на конкретных примерах, и в следующих подразделах демонстрируются различные формы асинхронного программирования на основе обратного вызова с использованием как клиентского JavaScript, так и Node.

Таймеры

Один из простейших видов асинхронности — это когда вы хотите выполнить некоторый код по истечении определенного времени, это можно сделать с помощью функции setTimeout().

setTimeout(checkForUpdates, 60000);

Вход в полноэкранный режим Выход из полноэкранного режима

Первым аргументом функции setTimeout() является функция, а вторым — интервал времени, измеряемый в миллисекундах. В предыдущем коде гипотетическая функция checkForUpdates() будет вызвана через 60 000 миллисекунд (1 минута) после вызова setTimeout().

setTimeout() вызывает указанную функцию обратного вызова один раз, не передавая никаких аргументов, а затем забывает о ней. Если вы пишете функцию, которая действительно проверяет наличие обновлений, вы, вероятно, хотите, чтобы она выполнялась многократно. Вы можете сделать это, используя setInterval() вместо setTimeout():

// Call checkForUpdates in one minute and then again every minute after that
let updateIntervalId = setInterval(checkForUpdates, 60000);

// setInterval() returns a value that we can use to stop the repeated
// invocations by calling clearInterval(). (Similarly, setTimeout()
// returns a value that you can pass to clearTimeout())
function stopCheckingForUpdates() {
    clearInterval(updateIntervalId);
}

Вход в полноэкранный режим Выход из полноэкранного режима

События

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

// Ask the web browser to return an object representing the HTML
// <button> element that matches this CSS selector
let okay = document.querySelector('#confirmUpdateDialog button.okay');

// Now register a callback function to be invoked when the user
// clicks on that button.
okay.addEventListener('click', applyUpdate);

Вход в полноэкранный режим Выход из полноэкранного режима

applyUpdate() — это гипотетическая функция обратного вызова, которая, как мы предполагаем, реализована где-то еще. Вызов document.querySelector() возвращает объект, представляющий один указанный элемент на веб-странице. Мы вызываем addEventListener() на этом элементе, чтобы зарегистрировать наш обратный вызов.

Сетевые события

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

function getCurrentVersionNumber(versionCallback) { // Note callback argument
    // Make a scripted HTTP request to a backend version API
    let request = new XMLHttpRequest();
    request.open("GET", "http://www.example.com/api/version");
    request.send();

    // Register a callback that will be invoked when the response arrives
    request.onload = function() {
        if (request.status === 200) {
            // If HTTP status is good, get version number and call callback.
            let currentVersion = parseFloat(request.responseText);
            versionCallback(null, currentVersion);
        } else {
            // Otherwise report an error to the callback
            versionCallback(response.statusText, null);
        }
    };
    // Register another callback that will be invoked for network errors
    request.onerror = request.ontimeout = function(e) {
        versionCallback(e.type, null);
    };
}

Войти в полноэкранный режим Выйти из полноэкранного режима

Код JavaScript на стороне клиента может использовать класс XMLHttpRequest плюс функции обратного вызова для выполнения HTTP-запросов и асинхронной обработки ответа сервера, когда он приходит.

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

Обратные вызовы и события в Node

Серверная среда JavaScript Node.js глубоко асинхронна и определяет множество API, использующих обратные вызовы и события. Например, API по умолчанию для чтения содержимого файла является асинхронным и вызывает функцию обратного вызова, когда содержимое файла было прочитано.

const fs = require("fs"); // The "fs" module has filesystem-related APIs
let options = {           // An object to hold options for our program
    // default options would go here
};

// Read a configuration file, then call the callback function
fs.readFile("config.json", "utf-8", (err, text) => {
    if (err) {
        // If there was an error, display a warning, but continue
        console.warn("Could not read config file:", err);
    } else {
        // Otherwise, parse the file contents and assign to the options object
        Object.assign(options, JSON.parse(text));
    }

    // In either case, we can now start running the program
    startProgram(options);
});

Вход в полноэкранный режим Выход из полноэкранного режима

Функция fs.readFile() Node принимает в качестве последнего аргумента обратный вызов с двумя параметрами. Она асинхронно считывает указанный файл, а затем вызывает обратный вызов. Если файл был прочитан успешно, она передает содержимое файла в качестве второго аргумента обратного вызова. Если произошла ошибка, то ошибка передается в качестве первого аргумента обратного вызова.

Node также определяет ряд API, основанных на событиях. Следующая функция показывает, как сделать HTTP-запрос на содержимое URL в Node. Она имеет два уровня асинхронного кода, обрабатываемого с помощью слушателей событий

const https = require("https");

// Read the text content of the URL and asynchronously pass it to the callback.
function getText(url, callback) {
    // Start an HTTP GET request for the URL
    request = https.get(url);

    // Register a function to handle the "response" event.
    request.on("response", response => {
        // The response event means that response headers have been received
        let httpStatus = response.statusCode;

        // The body of the HTTP response has not been received yet.
        // So we register more event handlers to to be called when it arrives.
        response.setEncoding("utf-8");  // We're expecting Unicode text
        let body = "";                  // which we will accumulate here.

        // This event handler is called when a chunk of the body is ready
        response.on("data", chunk => { body += chunk; });

        // This event handler is called when the response is complete
        response.on("end", () => {
            if (httpStatus === 200) {   // If the HTTP response was good
                callback(null, body);   // Pass response body to the callback
            } else {                    // Otherwise pass an error
                callback(httpStatus, null);
            }
        });
    });

    // We also register an event handler for lower-level network errors
    request.on("error", (err) => {
        callback(err, null);
    });
}

Вход в полноэкранный режим Выход из полноэкранного режима

Оцените статью
Procodings.ru
Добавить комментарий