Callbacks и Promise при загрузке

В PlayCanvas при разработке игр или приложений важным этапом является загрузка различных ресурсов, таких как текстуры, модели, звуковые файлы и другие данные. Этот процесс требует тщательной обработки, чтобы обеспечить плавную работу приложения, избежать сбоев и задержек в интерфейсе. Для этого используются механизмы callbacks и Promise для асинхронной загрузки и обработки ресурсов. Разберём, как эффективно использовать эти подходы.

Callbacks в PlayCanvas

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

Для загрузки ресурса с использованием callbacks в PlayCanvas применяется метод load, который может принимать callback функцию в качестве второго параметра. Это позволяет отложить выполнение кода до тех пор, пока ресурс не будет загружен. Пример использования:

var asset = new pc.Asset('myTexture', 'texture', {
    url: 'path/to/texture.png'
});

asset.on('load', function() {
    console.log('Texture loaded!');
    // Здесь можно выполнить действия после загрузки
    var texture = asset.resource;
    material.diffuseMap = texture;
    material.update();
});

app.assets.add(asset);
app.assets.load(asset);

В данном примере создаётся объект asset, который представляет собой текстуру. С помощью метода on('load') добавляется callback, который будет вызван после того, как текстура полностью загрузится. Внутри этого callback можно работать с ресурсом, например, назначить его на материал.

В случае ошибки загрузки также можно использовать callback:

asset.on('error', function(err) {
    console.error('Error loading texture:', err);
});

Таким образом, использование callbacks позволяет контролировать порядок выполнения кода в асинхронной среде.

Promise для асинхронной загрузки

С появлением Promises в JavaScript был разработан более удобный способ работы с асинхронными операциями, что значительно улучшило читаемость и поддержку кода. PlayCanvas также поддерживает работу с Promise, что позволяет избежать “callback hell” — ситуации, когда множество вложенных callbacks затрудняет чтение и поддержку кода.

Для того чтобы использовать Promises при загрузке ресурсов, можно создать обёртку над методом load. Вместо того, чтобы передавать callback, мы возвращаем Promise, который разрешается (resolve) при успешной загрузке и отклоняется (reject) при ошибке. Пример:

function loadAsset(asset) {
    return new Promise(function(resolve, reject) {
        asset.on('load', function() {
            resolve(asset.resource);
        });

        asset.on('error', function(err) {
            reject(err);
        });

        app.assets.add(asset);
        app.assets.load(asset);
    });
}

var asset = new pc.Asset('myTexture', 'texture', {
    url: 'path/to/texture.png'
});

loadAsset(asset)
    .then(function(texture) {
        console.log('Texture loaded!');
        material.diffuseMap = texture;
        material.update();
    })
    .catch(function(error) {
        console.error('Error loading texture:', error);
    });

Здесь создаётся функция loadAsset, которая возвращает Promise. В случае успешной загрузки вызывается resolve(), и ресурс передаётся в .then(). Если загрузка завершилась ошибкой, вызывается reject(), и ошибка обрабатывается в .catch().

Асинхронная загрузка нескольких ресурсов с использованием Promise.all

Для загрузки нескольких ресурсов одновременно можно использовать Promise.all. Это позволяет загрузить несколько ассетов, а затем выполнить определённые действия после того, как все ресурсы будут загружены. Пример:

var textureAsset = new pc.Asset('texture', 'texture', {
    url: 'path/to/texture.png'
});
var modelAsset = new pc.Asset('model', 'model', {
    url: 'path/to/model.json'
});

function loadAssets() {
    return Promise.all([
        loadAsset(textureAsset),
        loadAsset(modelAsset)
    ]);
}

loadAssets()
    .then(function(results) {
        var texture = results[0];
        var model = results[1];
        console.log('All assets loaded!');
        material.diffuseMap = texture;
        material.update();
        // Здесь можно работать с моделью
    })
    .catch(function(error) {
        console.error('Error loading assets:', error);
    });

Promise.all принимает массив из промисов и возвращает новый промис, который будет разрешён только тогда, когда все промисы в массиве будут выполнены успешно. Если хотя бы один из промисов завершится с ошибкой, catch поймает ошибку и обработает её.

Разница между Callbacks и Promise

Callbacks — это базовый механизм асинхронной обработки, но с ростом сложности кода может возникать ситуация, когда управление становится трудным, особенно когда несколько функций друг в друге вызываются последовательно. В таких случаях “callback hell” превращает код в трудночитаемый и труднопонимаемый. Также сложно обработать ошибки, так как их нужно обрабатывать в каждом callback.

Promises значительно упрощают работу с асинхронным кодом, позволяют использовать методы .then(), .catch(), .finally(), а также облегчают работу с асинхронными операциями, которые нужно выполнить одновременно или последовательно. Они предоставляют более чистый и современный способ работы с асинхронными операциями.

Резюме

Использование callbacks и Promise в PlayCanvas позволяет эффективно управлять загрузкой ассетов и их обработкой. Выбор между ними зависит от сложности приложения и предпочтений разработчика. В небольших проектах может быть достаточно использования callbacks, однако для более крупных и сложных проектов использование Promise предоставляет более удобный и читаемый способ работы с асинхронным кодом.