我在从一个网站上提取数据。被拉取的数据是分页的。向第一个页面发出请求时,会收到一个包含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。
我想要做的是使用Promise来实现这一点。除了我不知道如何创建一个以类似方式工作的循环,因为每个请求都依赖于最后一个请求。
使用promises,这是如何工作的?
这是我目前的解决方案,当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发布于 2016-08-22 17:31:37
由于该过程是异步的,因此根本不使用循环结构;只需使用调用自身的函数(通过另一个函数间接调用)。
在你的例子中,既然你已经说过你想用promises来实现它,下面是你怎么做的(实际上最容易用代码表达);
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版本看起来基本相同。)
发布于 2016-08-22 17:49:44
另一种方法是缩短您正在使用的异步函数,并在此基础上进行构建。
这种方法的好处是功能是模块化的,因此如果您想使用promises发出其他类型的请求,则可以重用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
});https://stackoverflow.com/questions/39075779
复制相似问题