2016-08-22 5 views
2

Я вытаскиваю данные с веб-сайта. Вытаскиваемые данные деактивируются. При отправке запроса на первую страницу получен ответ, содержащий nextCursor. Этот курсор должен использоваться для получения результатов для страницы 2. Для каждого запроса страницы требуется nextCursor.Использование обещаний и циклов?

Я изо всех сил пытаюсь реализовать это с помощью обещаний, потому что я не могу найти никакого способа петли. Это, как я предполагаю, что это работает без Promises (не проверял, но он показывает, что я пытаюсь сделать):

let nextCursor = argv.initalCursor 

do { 
    let r = request('http://example.com/items.php?cursor=' + nextCursor, function(err, resp, body) { 
    if(err) throw new Error(err) 

    // Do something with the data 

    nextCursor = JSON.parse(body)['nextCursor'] 
    }) 
} while(nextCursor) 

Как вы можете видеть количество итераций в цикле неизвестно. Он будет зацикливаться до тех пор, пока в ответе не будет nextCursor.

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

Как это будет работать с обещаниями?

Вот мое текущее решение, которое не работает, когда return self.cursorRequest. Сценарий просто останавливает выполнение.

'use strict' 

let Promise = require('bluebird') 
let _ = require('lodash') 

class Event { 
    constructor(session) { 
    this.session = session 
    this.scrapedIDs = [] // I don't like this! 
    } 

    parseGuestsAndCursor(json, guestType) { 
    let ids = json['payload'][guestType]['sections'][2][1].map(function(user) { 
     return user['uniqueID'] 
    }) 

    return { 
     ids: _.uniq(ids), 
     cursor: json['payload'][guestType]['cursor'] 
    } 
    } 

    cursorRequest(cursor, eventID, guestType) { 
    let self = this 

    return new Promise(function(resolve, reject) { 
     let url = `https://example.com/events/typeahead/guest_list/?event_id=${eventID}&tabs[0]=${guestType}&order[${guestType}]=affinity&bucket_schema[${guestType}]=friends&cursor[${guestType}]=${cursor}&dpr=1&__user=${self.session.uid}&__a=1` 

     self.session.request(url, function(err, resp, body) { 
     if(err) reject(err) 
     let json 

     try { 
      json = JSON.parse(body.substring(9)) 
     } catch(err) { 
      reject(err) 
     } 

     resolve(self.parseGuestsAndCursor(json, guestType)) 
     }) 
    }) 
    } 

    members(eventID, limit, guestType) { 
    let self = this 
    let ids = [] 

    return new Promise(function(resolve, reject) { 
     let url = `https://example.com/events/typeahead/guest_list/?event_id=${eventID}&tabs[0]=watched&tabs[1]=going&tabs[2]=invited&order[declined]=affinity&order[going]=affinity&order[invited]=affinity&order[maybe]=affinity&order[watched]=affinity&order[ticket_purchased]=affinity&bucket_schema[watched]=friends&bucket_schema[going]=friends&bucket_schema[invited]=friends&bucket_schema[ticket_purchased]=friends&dpr=1&__user=${self.session.uid}&__a=1` 

     self.session.request(url, function(err, resp, body) { 
     if(err) reject(new Error(err)) 
     let json, guests 

     try { 
      json = JSON.parse(body.substring(9)) 
      guests = self.parseGuestsAndCursor(json, guestType) 
     } catch(err) { 
      reject(err) 
     } 

     self.cursorRequest(guests.cursor, eventID, guestType).then(function(guests) { 

      self.scrapedIDs.concat(guests.ids).map(function(user) { 
      return user['uniqueID'] 
      }) 

      if(guests.cursor) { 
      return self.cursorRequest(guests.cursor, eventID, guestType) 
      } 
      else { 
      resolve(self.scrapedIDs) 
      } 
     }) 
     }) 
    }) 
    } 
} 

module.exports = Event 
+0

Я не вижу никаких обещаний там вообще , –

+0

@ T.J.Crowder Нет, потому что я не уверен, как реализовать то, что я пытаюсь сделать с обещаниями. Вот почему я спрашиваю, как это можно сделать с обещаниями? Я не требую решения, просто указатель на любые ресурсы, которые могут вам помочь. – BugHunterUK

+0

Вам нужно обещание подождать, пока все данные не будут восстановлены до разрешения? –

ответ

3

Поскольку процесс является асинхронным, вы вообще не используете петлевую конструкцию; вы просто используете функцию, которая вызывает себя (косвенно через другую функцию).

В вашем случае, поскольку вы сказали, что хотите реализовать это с обещаниями, вот как вы это делаете (проще всего выразить в коде);

var p = new Promise(function(resolve, reject) { 
    let nextCursor = argv.initialCursor; 

    doRequest(); 

    function doRequest() { 
     request('http://example.com/items.php?cursor=' + nextCursor, handleResult); 
    } 

    function handleResult(err, resp, body) { 
     if (err) { 
      // Got an error, reject the promise 
      reject(err); 
     } else { 
      // Do something with the data 

      // Next? 
      nextCursor = JSON.parse(body)['nextCursor']; 
      if (nextCursor) { 
       // Yup, do it 
       doRequest(); 
      } else { 
       // No, we're done 
       resolve(/*...resolution value here...*/); 
      } 
     } 
    } 
}); 

(версия ES2015 выглядит в основном то же самое.)

+0

Это не работает, потому что я получаю «Максимальный размер стека вызовов» – BugHunterUK

+0

@BugHunterUK: У вас должна быть опечатка в той версии, в которой вы работаете. Вы случайно не положили '()' после 'handleResult' в' request (..., handleResult); 'строка, случайно? Важно, чтобы они * не * были там, мы хотим передать ссылку на функцию, а не называть ее. –

1

Еще один способ сделать это состоит в promisify асинхронной функции вы используете, и построить на этом.

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

let nextCursor = argv.initalCursor 

function requestPromise(url) { 
    return new Promise(function (resolve, reject) { 
     request(url, function (err, resp, body) { 
      if (err) { reject(new Error(err)); } 
      else { resolve({ resp: resp, body: body}); } 
     }); 
    }); 
} 

function queryCursor(cursor) { 
    return requestPromise('http://example.com/items.php?cursor=' + cursor) 
     .then(function (result) { 
      // do something with result 

      var nextCursor = JSON.parse(result.body).nextCursor; 

      if (nextCursor) { 
       return queryCursor(nextCursor); 
      } 
     }); 
} 

queryCursor(nextCursor) 
    .catch(function (err) { 
     // deal with err 
    }); 
+0

Я обновил свой вопрос с помощью моего текущего решения. Кажется, я не могу заставить его работать. Когда я возвращаюсь, он просто останавливает скрипт. – BugHunterUK

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