使用async和await控制爬虫执行
为了解决js的回调嵌套问题(金字塔),ES6新增了Promise和Generator来解决此问题。但我个人觉得Promise需要不断then
,虽然没有出现金字塔现象,但总觉得还不够直观,而Generator也需要next
依然不够直观易懂。随着Nodejs 7.0的发布,是时候玩玩Async函数了。
今天刚好用Async函数来做了一个爬虫,个人觉得代码的易读性比Promise和Generator好。如果你还不会Async,可以看看阮一峰写的文章。
Nodejs 7.0开启async/await功能
默认Nodejs 7.0并没有开启该功能,需要我们在启动程序时传入参数开启,启动方法:
node --harmony_async_await index.js
爬虫执行的步骤
- 获取邀请码
- 通过邀请码进行注册账号
- 登陆网站
- 获取需要的信息
使用回调的写法
// 获取邀请码
console.log("正在获取邀请码...");
request(inviteUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
/// ...
let code;
// 注册
request(registerUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
// 登录
console.log(json, "正在登录...");
request(loginUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
/// 获取信息
request(anyUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body, "获取信息成功");
} else {
console.log("获取信息:", error.message);
}
});
} else {
console.log("登录:", error.message);
}
});
} else {
console.log("注册账号:" + error.message);
}
});
} else {
console.log("获取邀请码失败:" + error.message);
}
});
这种多层嵌套,我相信你已经看的很恶心了。
使用async/await改写
获取邀请码
function getInvite() {
return new Promise((resolve, reject) => {
console.log("正在获取邀请码...");
request(inviteUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
/// ...
resolve(code);
} else {
reject("获取邀请码失败:" + error.message);
}
});
});
}
注册账号
function registry(){
console.log("正在注册账号...");
return new Promise((resolve, reject) => {
request(registerUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
let json = JSON.parse(body);
if (json.code === 200 && json.data.error === 0) {
console.log(json, "正在登录...");
resolve();
} else {
reject(json);
}
} else {
reject("注册账号:" + error.message);
}
});
});
}
登录
function login() {
let that = this;
return new Promise((resolve, reject) => {
request(loginUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
let json = JSON.parse(body);
if (json.code === 200 && json.data.error === 0) {
resolve(6);
} else {
console.log(json.data.message);
reject(json.data.message);
}
} else {
reject("登录:", error.message);
}
});
});
}
获取需要的信息或干其他事情
function doSomething(){
return new Promise((resolve, reject) => {
request(anyUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
let json = JSON.parse(body);
if (json.code === 200 && json.data.error === 0) {
console.log("获取信息成功");
resolve(json);
} else {
console.log(json.data.message);
reject(json.data.message);
}
} else {
reject("获取信息:", error.message);
}
});
});
}
按步骤执行代码
async function start(){
let data;
try {
let code = await getInvite();
await register(code);
await login();
data = await doSomething();
return data;
} catch (err) {
console.log(err);
}
}
start().then(data => console.log(data));
整个代码流程就是这样,是不是觉得使用了Async代码结构清晰很多。如果你对Promise和Generator熟悉的话,有没有发现在Async中都有它们的身影,如在代码中同样需要用到Promise,再如最后执行代码那步有没有发现关键词async
像Generator函数中的*
,await
像Generator函数中的yeild
关键词。
完整的代码实例请移步至 fetch-ss