8

Как преобразовать существующий API с обратными вызовами в промисы?

9

Я хочу работать с промисами, но у меня есть API, который использует колбэки в следующих форматах:

1. Загрузка DOM или другое одноразовое событие:

window.onload; // установить колбэк
...
window.onload = function() {

};

2. Простой колбэк:

function request(onChangeHandler) {
    ...
}
request(function() {
    // произошло изменение
    ...
});

3. Колбэк в стиле Node ("nodeback"):

function getStuff(dat, callback) {
    ...
}
getStuff("dataParam", function(err, data) {
    ...
});

4. Целая библиотека с колбэками в стиле Node:

API;
API.one(function(err, data) {
    API.two(function(err, data2) {
        API.three(function(err, data3) {
            ...
        });
    });
});

Как я могу работать с этими API, используя промисы? Как мне "промисифицировать" их?

5 ответ(ов)

0

Чтобы преобразовать функцию, использующую обратные вызовы, в промис в Node.js, можно следовать приведенному примеру. Ниже показан процесс преобразования:

Перед преобразованием в промис:

var request = require('request'); // Модуль для работы с HTTP

function requestWrapper(url, callback) {
    request.get(url, function (err, response) {
      if (err) {
        callback(err);
      } else {
        callback(null, response);             
      }      
    })
}

requestWrapper(url, function (err, response) {
    console.log(err, response)
})

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

После преобразования в промис:

var request = require('request');

function requestWrapper(url) {
  return new Promise(function (resolve, reject) { // Возвращаем промис
    request.get(url, function (err, response) {
      if (err) {
        reject(err); // Отклоняем промис
      } else {
        resolve(response); // Исполняем промис
      }
    })
  })
}

requestWrapper('http://localhost:8080/promise_request/1').then(function(response){
    console.log(response); // Обработка успешного ответа
}).catch(function(error){
    console.log(error); // Обработка ошибки
})

В этом примере requestWrapper теперь возвращает промис. При получении ошибки промис отклоняется, а в случае успешного ответа — исполняется.

Если вам нужно обработать несколько запросов:

var allRequests = [];
allRequests.push(requestWrapper('http://localhost:8080/promise_request/1')) 
allRequests.push(requestWrapper('http://localhost:8080/promise_request/2'))
allRequests.push(requestWrapper('http://localhost:8080/promise_request/5'))    

Promise.all(allRequests).then(function (results) {
  console.log(results); // Результат будет массивом, содержащим ответы каждого промиса
}).catch(function (err) {
  console.log(err);
});

В этом примере мы создаем массив allRequests, в который добавляем несколько запросов, и затем используем Promise.all, чтобы обработать их параллельно. Если все запросы выполнены успешно, мы получаем массив результатов; в случае ошибки — обработка ошибки через catch.

Таким образом, использование промисов позволяет более удобно управлять асинхронной логикой в Node.js.

0

Я не думаю, что предложение использовать window.onload от @Benjamin будет работать всегда, так как оно не проверяет, было ли вызвано событие после полной загрузки. У меня были с этим проблемы много раз. Вот версия, которая всегда должна работать:

function promiseDOMready() {
    return new Promise(function(resolve) {
        if (document.readyState === "complete") return resolve();
        document.addEventListener("DOMContentLoaded", resolve);
    });
}
promiseDOMready().then(initOnLoad);

Этот код создает промис, который разрешается, когда DOM полностью загружен. Если состояние документа уже "complete", промис сразу же разрешается. В противном случае добавляется обработчик события DOMContentLoaded, который разрешит промис, когда событие произойдет. Таким образом, вы всегда получите гарантированное срабатывание обработчика, независимо от времени вызова.

0

Простая обобщённая функция, которую я обычно использую

const promisify = (fn, ...args) => {
  return new Promise((resolve, reject) => {
    fn(...args, (err, data) => {
      if (err) {
        return reject(err);
      }
      resolve(data);
    });
  });
};

Как её использовать

  • Функция promisify принимает функцию с обратным вызовом:
const cb = (result) => `Результат: ${result}`;

const sum = (a, b, cb) => {
  const result = a + b;
  cb(result); // передача аргументов в функцию обратного вызова
}

// Использование утилиты
const promise = promisify(sum, 3, 1, cb);
promise.then(x => console.log(x)); // 4

Вы, возможно, не ищете этот ответ, но он поможет понять внутреннее устройство доступных утилит.

0

Вы можете использовать нативные промисы JavaScript с Node.js.

Вот пример кода, который демонстрирует, как можно использовать промисы в вашем приложении на Node.js с Express:

/**
* Created by dixit-lab on 20/6/16.
*/

var express = require('express');
var request = require('request'); // Упрощенный HTTP-клиент.

var app = express();

function promisify(url) {
    return new Promise(function (resolve, reject) {
        request.get(url, function (error, response, body) {
            if (!error && response.statusCode == 200) {
                resolve(body);
            }
            else {
                reject(error);
            }
        });
    });
}

// Получить все альбомы пользователя, который опубликовал пост с ID 100
app.get('/listAlbums', function (req, res) {
    // Получаем пост с ID 100
    promisify('http://jsonplaceholder.typicode.com/posts/100').then(function (result) {
        var obj = JSON.parse(result);
        return promisify('http://jsonplaceholder.typicode.com/users/' + obj.userId + '/albums');
    })
    .catch(function (e) {
        console.log(e);
        res.status(500).send('Ошибка при получении данных.');
    })
    .then(function (result) {
        res.end(result);
    });
});

var server = app.listen(8081, function () {
    var host = server.address().address;
    var port = server.address().port;

    console.log("Пример приложения запущен по адресу http://%s:%s", host, port);
});

// Запустите веб-сервис в браузере: http://localhost:8081/listAlbums

Обратите внимание на функцию promisify, которая возвращает промис, использующий библиотеку request для выполнения HTTP-запросов. В эндпоинте /listAlbums мы сначала получаем пост с ID 100, затем, используя userId из этого поста, запрашиваем все альбомы пользователя. Ошибки обрабатываются с помощью .catch, и в случае их возникновения клиент получает сообщение об ошибке с статусом 500.

0

Чтобы преобразовать колбэк API в промисы с помощью простого JavaScript, можно использовать следующий подход. Рассмотрим функцию get, которая выполняет запрос к указанному URL и использует колбэк для обработки результата.

function get(url, callback) {
    var xhr = new XMLHttpRequest();
    xhr.open('get', url);
    xhr.addEventListener('readystatechange', function () {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
                console.log('успех ... вызываем колбэк ...');
                callback(null, JSON.parse(xhr.responseText));
            } else {
                console.log('ошибка ... вызываем колбэк с данными об ошибке ...');
                callback(xhr, null);
            }
        }
    });
    xhr.send();
}

/**
 * @function promisify: преобразует функции с колбэками в промисы
 * @description принимает функцию и преобразует её в промис
 * @params {function} fn функция для преобразования
 * @params {array} args массив аргументов для функции
 * @return {function} преобразованная в промис функция
 */
function promisify(fn) {
    return function () {
        var args = Array.prototype.slice.call(arguments);
        return new Promise(function(resolve, reject) {
            fn.apply(null, args.concat(function (err, result) {
                if (err) reject(err);
                else resolve(result);
            }));
        });
    }
}

var get_promisified = promisify(get);
var promise = get_promisified('some_url');
promise.then(function (data) {
    // соответствует функции resolve
    console.log('успешная операция: ', data);
}, function (error) {
    console.log(error);
});

В этом коде мы создали функцию get, которая использует XMLHttpRequest для обработки HTTP-запросов. Затем мы создали функцию promisify, которая принимает эту функцию и возвращает новую функцию, которая возвращает промис. При вызове get_promisified возвращается промис, позволяя использовать then для обработки успешного или ошибочного результата.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь