2016-11-09 9 views
0

Имейте процесс NodeJS, который обращается к веб-сервису для чего-то называемого Kudos. Эти награды отправляются от одного человека другому человеку или группе людей. То, что я пытаюсь сделать, это создать одно сообщение, имеющее следующее:NodeJS Promises: Правильный способ объединения нескольких запросов HTTP-запросов


Kudos от {плаката} до {приемника/с}

{Престижность сообщений}


В настоящее время У меня есть процесс, который правильно работает для плаката на одном приемнике. Я борюсь за то, чтобы он работал с получением нескольких имен получателей.

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

JSON данных, которая содержит множество пользователей выглядит примерно так:

"notes_user": [ 
    { 
    "id": "1060", 
    "note_id": "795", 
    "user_id": "411" 
    }, 
    { 
    "id": "1061", 
    "note_id": "795", 
    "user_id": "250" 
    }, 
    { 
    "id": "1062", 
    "note_id": "795", 
    "user_id": "321" 
    } 
], 

Вот функция, которая делает большую часть работы:

getMaxId возвращает индекс базы данных из этой высшей престижности в настоящее время обработанный, и getKudos просто возвращает набор данных json «kudos».

function promisifiedKudos() { 
var maxid; 
var newmaxid; 

Promise.all([getMaxId(), getKudos()]) 
    .then(function(results) { 
     maxid = results[0]; 

     var kudos = results[1]; 
     newmaxid = kudos[0].id; 
     return kudos.filter(function(kudo) { 
      if (maxid < kudo.id) { 
       return kudo; 
      } 
     }) 
    }) 
    .each(function(kudo) { 
     return getTribeUserName(kudo); 
    }) 
    .then(function(results) { 
     return results.map(function(kudo) { 
      var message = "Kudos from " + kudo.poster.full_name + " to " + kudo.kudo_receiver_full_name + "\r\n"; 
      message += "\r\n"; 
      return message += entities.decode(striptags(kudo.note)); 
     }) 
    }) 
    .each(function(message) { 
     return postStatus(message); 
    }) 
    .then(function() { 
     var tribehr = db.get('tribehr'); 
     console.log(new Date().toString() + ":Max ID:" + newmaxid); 
     tribehr.update({ endpoint: "kudos" }, { $set: { id: newmaxid } }); 
    }) 
    .done(function(errors) { 
     console.log("Run Complete!"); 
     return "Done"; 
    }); 
} 

Вспомогательная функция getTribeUserName()

function getTribeUserName(kudo) { 
return new Promise(function(fulfill, reject) { 
    var id = kudo.notes_user[0].user_id; 
    var options = { 
     url: "https://APIURL.com/users/" + id + ".json", 
     method: "GET", 
     headers: { 
      "Authorization": "Basic " + new Buffer("AUTHCODE" + AUTHKEY).toString('base64') 
     } 
    } 
    request.getAsync(options).then(function(response) { 
     if (response) { 
      var data = JSON.parse(response.body) 
      kudo.kudo_receiver_full_name = data.User.full_name; 
      fulfill(kudo); 
     } else { 
      reject("Get Tribe User Name Failed"); 
     } 
    }); 
}); 
} 

Я попытался добавить вспомогательную функцию, которая вызывает getTribeUserName(), который выглядит следующим образом:

function getTribeUsers(kudo) { 
return new Promise(function(fulfill, reject) { 
    kudo.notes_user.map(function(user) { 
     //Make calls to a getTribeUserName 
    }) 
}); 
} 

Но результат что имена пользователей не определены, когда окончательное сообщение собрано вместе.

Любые указатели в том, как использовать обещания лучше, были бы чрезвычайно полезными. Это действительно мой первый удар с ними, и я надеюсь, что я пойду в правильном направлении. Я знаю, что мне нужно добавить проверку ошибок, но в настоящее время я просто пытаюсь заставить процесс работать для нескольких пользователей.

+0

Какую версию узла вы используете? Кроме того, какая библиотека Promise? '.each()' и '.done()' не являются стандартными функциями. –

+0

_ «Я могу легко получить обещания работать для одного пользователя» _ Повторить процесс для каждого пользователя? – guest271314

+0

Задумывались ли вы об использовании событий? Каждый «приемник» может инициировать событие, которое будет выполнять работу. – ppovoski

ответ

0

Если вам нужно использовать результат обещания, переданного как параметр функции resolve, тогда вы можете поймать его в обратном вызове .

Если вам нужно передать некоторые данные, полученные в рамках then метода цепи к другому then вы просто должны вернуть его и поймать его через onFulfilled обратного вызова следующего then.

object.somePromise().then(function(param){ 
    var data = someFunction(); 
    return data; 
}).then(function(param){ 
    //param holds the value of data returned by the previous then 
    console.log(param); 
}); 
0

Если это вопрос получения нескольких TribeUserNames асинхронно, то вам нужно как-то агрегированных обещаний, возвращаемых несколькими вызовами getTribeUserNames().

Вы можете написать Promise.all(array.map(mapper)), но Bluebird предоставляет более удобный Promise.map(array, mapper).

Bluebird's .spread() также удобен для ссылок maxid и kudos.

Здесь в качестве простой форме, как я могу управлять:

function promisifiedKudos() { 
    return Promise.all([getMaxId(), getKudos()]) 
    .spread(function(maxid, kudos) { 
     var newmaxid = kudos[0].id; 
     // The following line filters (synchronously), adds TribeUserNames (asynchronously), and delivers an array of processed kudos to the next .then(). 
     return Promise.map(kudos.filter((kudo) => kudo.id > maxid), getTribeUserName) 
     .then(function(filteredKudosWithTribeUserNames) { // in practice, shorten arg name to eg `kudos_` 
      return Promise.map(filteredKudosWithTribeUserNames, function(kudo) { 
       return postStatus("Kudos from " + kudo.poster.full_name + " to " + kudo.kudo_receiver_full_name + "\r\n\r\n" + entities.decode(striptags(kudo.note))); 
      }); 
     }) 
     .then(function() { 
      var tribehr = db.get('tribehr'); 
      console.log(new Date().toString() + ":Max ID:" + newmaxid); 
      return tribehr.update({ endpoint: 'kudos' }, { $set: { 'id': newmaxid } }); 
     }); 
    }) 
    .then(function() { 
     console.log('Run Complete!'); 
    }).catch(function(error) { 
     console.log(error); 
     throw error; 
    }); 
} 

getTribeUserName() потребности вернуть обещание, и может быть записана следующим образом:

function getTribeUserName(kudo) { 
    var options = { 
     'url': 'https://APIURL.com/users/' + kudo.notes_user[0].user_id + '.json', 
     'method': 'GET', 
     'headers': { 
      'Authorization': 'Basic ' + new Buffer('AUTHCODE' + AUTHKEY).toString('base64') 
     } 
    } 
    return request.getAsync(options).then(function(response) { 
// ^^^^^^ 
     if(response) { 
      kudo.kudo_receiver_full_name = JSON.parse(response.body).User.full_name; 
     } else { 
      throw new Error(); // to be caught immediately below. 
     } 
     return kudo; 
    }).catch(function(error) { // error resistance 
     kudo.kudo_receiver_full_name = 'unknown'; 
     return kudo; 
    }); 
} 

Дополнительные примечания:

  • От гнезда Promise.map(...).then(...).then(...) в обращении .spread(), newmaxid остается доступным через закрытие, избегая необходимости в уродливом внешнем var.
  • Promise.map() используется во второй раз при условии, что postStatus() является асинхронным. Если это не так, код все равно будет работать, хотя он может быть написан несколько иначе.

 Смежные вопросы

  • Нет связанных вопросов^_^