Вызов Api с помощью обещаний javascript в рекурсии
Я хотел бы использовать Gitter api, чтобы получить все сообщения из комнаты.
Что мне нужно сделать, так это отправить запрос get api, например, с 50 элементами, onComplete мне нужно отправить другой запрос с 50 элементами и пропустить 50 элементов, которые я уже получил. Делайте этот запрос до тех пор, пока они не вернут какие-либо предметы. Итак:
- Отправить запрос api
- json разобрать его
- : запрос содержит элементы
- Сделайте sql-запрос с этими элементами
- продолжить запрос
- Отправить следующий api запрос (рекурсия?)
- ? если в следующем запросе api больше нет элементов-показать сообщение done
- : запрос не содержит элементов
- прервать сообщение
class Bot {
//...
_mysqlAddAllMessages(limit, skip) {
promise('https://api.gitter.im/v1/rooms/' + this.room + '/chatMessages' +
'?access_token=' + config.token + '&limit=' + limit + '&skip=' + skip)
.then(function (response) {
return new Promise(function (resolve, reject) {
response = JSON.parse(response);
if (response.length) {
console.log(`Starting - limit:${limit}, skip:${skip}`);
resolve(response);
}
})
}).then(response => {
let messages = response,
query = 'INSERT INTO messages_new (user_id, username, message, sent_at) VALUES ';
for (let message of messages) {
let userId = message.fromUser.id,
username = message.fromUser.username,
text = message.text.replace(/["\]/g, '|'),
date = message.sent;
query += '("' + userId + '", "' + username + '", "' + text + '", "' + date + '"), ';
}
query = query.substr(0, query.length - 2);
return new Promise((resolve, reject) => {
this.mysql.getConnection((error, connection) => {
connection.query(query, (err) => {
if (err) {
reject(`Mysql Error: ${err}`);
} else {
connection.release();
resolve(console.log(`Added ${messages.length} items.`));
}
});
});
});
})
.then(()=> {
// what to do here
return this._mysqlAddAllMessagesf(limit, skip += limit)
})
.catch(function (er) {
console.log(er);
})
.finally(function () {
console.log('Message fetching completed.');
});
}
}
let bot = new Bot();
bot._mysqlAddAllMessages(100, 0);
Может быть, вы можете проверить и помочь мне? Или предоставить аналогичный код для таких вещи?
Обновление
Вот до чего я переработал код: jsfiddle
1 ответ:
Ваш код меня сильно запутал. Самый простой способ использовать обещания с асинхронными операциями - "обещать" существующие асинхронные операции, а затем написать всю логику после этого, используя обещания. "Обещать" что-то означает генерировать или писать функцию-оболочку, которая возвращает обещание, а не использует только обратный вызов.
Во-первых, давайте рассмотрим общую логику. В соответствии с вашим вопросом, Вы сказали, что у вас есть API, который вы хотите вызвать, чтобы получить 50 элементов одновременно, пока вы не получите их всех. Это можно сделать с помощью рекурсивной структуры. Создайте внутреннюю функцию, которая выполняет извлечение и возвращает обещание, и каждый раз, когда она завершается, вызывайте ее снова. Предположим, что здесь задействованы две основные функции: одна с именемgetItems(), которая получает элементы из вашего API и возвращает обещание, и другая с именемstoreItems(), которая хранит эти элементы в вашей базе данных.Этот код использует цепочку обещаний, которая является немного продвинутой, но чрезвычайно полезной функцией обещаний. Когда вы возвращаете обещание от обработчикаfunction getAllItems(room, chunkSize, token) { var cntr = 0; function getMore() { return getItems(room, cntr, chunkSize, token).then(function(results) { cntr += results.length; if (results.length === chunkSize) { return storeItems(results).then(getMore); } else { return storeItems(results); } }); } return getMore(); }.then(), оно привязывается к предыдущему обещанию, автоматически связывая их все вместе в серию операций. Конечный результат возврата или ошибка затем возвращаются обратно через исходное обещание исходному вызывающему объекту. Аналогично, любая ошибка, которая может произойти в этой цепочке, передается обратно к исходному вызывающему объекту. Это чрезвычайно полезно в сложных функциях с несколькими асинхронными операциями, где вы не можете просто вернуть или бросьте, если используете регулярные обратные вызовы.Тогда это будет называться так:
Теперь я поработаю над некоторыми примерами для созданных многообещающих версий ваших вызовов нижних уровней для реализацииgetAllItems(this.room, 50, config.token).then(function() { // finished successfully here }, function(err) { // had an error here });getItems()иstoreItems(). Сейчас вернусь с ними.Я не вполне понимаю все детали ваших асинхронных операций, поэтому это не будет полностью рабочий пример, но должен проиллюстрировать общую концепцию, и вы можете задать любые необходимые уточняющие вопросы о реализация.
При обещании функции главное, что вы хотите сделать, - это инкапсулировать грязную работу обработки обратного вызова и условий ошибки в одну основную функцию, которая возвращает обещание. Это затем позволяет использовать эту функцию в хорошем чистом потоковом коде на основе обещаний и позволяет использовать действительно большие возможности обработки ошибок обещаний в потоке управления.
Для запроса элементов, похоже, вы создаете URL-адрес, который занимает кучу аргументы в URL-адресе, и вы получите результаты обратно в JSON. Я предполагаю, что это узел.JS окружающая среда. Итак, вот как вы можете выполнить реализацию
getItems()с помощью узла.модуль jsrequest(). Это возвращает обещание, разрешенное значение которого будет уже проанализированным объектом Javascript, представляющим результаты вызова api.function getItems(room, start, qty, token) { return new Promise(function(resolve, reject) { var url = 'https://api.gitter.im/v1/rooms/' + room + '/chatMessages' + '?access_token=' + token + '&limit=' + qty + '&skip=' + start; request({url: url, json: true}, function(err, msg, result) { if (err) return reject(err); resolve(result); }); }); }Для хранения предметов мы хотим сделать то же самое. Мы хотим создать функцию, которая принимает данные для хранения в качестве аргументов и возвращает обещание и он делает всю грязную работу внутри функции. Итак, логически вы хотите иметь такую структуру:
function storeItems(data) { return new Promise(function(resolve, reject) { // do the actual database operations here // call resolve() or reject(err) when done }); }Извините, но я не совсем понимаю, что вы делаете с вашей базой данных mySql достаточно, чтобы полностью заполнить эту функцию. Надеюсь, эта структура даст вам достаточно идей, как закончить его или задать несколько вопросов, если вы застряли.
Примечание: Если вы используете библиотеку Promise, такую как Bluebird, чтобы добавить дополнительную функциональную функциональность promise, то promisifying существующая операция-это то, что встроено в Bluebird, поэтому
getItems()просто становится таким:var Promise = require('bluebird'); var request = Promise.promisifyAll(require('request')); function getItems(room, start, qty, token) { var url = 'https://api.gitter.im/v1/rooms/' + room + '/chatMessages' + '?access_token=' + token + '&limit=' + qty + '&skip=' + start; return request.getAsync({url: url, json: true}); }