发布于 4 年前 ,更新于 4 年前 javascript,node

使用async和await控制爬虫执行

为了解决js的回调嵌套问题(金字塔),ES6新增了PromiseGenerator来解决此问题。但我个人觉得Promise需要不断then,虽然没有出现金字塔现象,但总觉得还不够直观,而Generator也需要next依然不够直观易懂。随着Nodejs 7.0的发布,是时候玩玩Async函数了。 今天刚好用Async函数来做了一个爬虫,个人觉得代码的易读性比PromiseGenerator好。如果你还不会Async,可以看看阮一峰写的文章

Nodejs 7.0开启async/await功能

默认Nodejs 7.0并没有开启该功能,需要我们在启动程序时传入参数开启,启动方法:

node --harmony_async_await index.js
爬虫执行的步骤
  1. 获取邀请码
  2. 通过邀请码进行注册账号
  3. 登陆网站
  4. 获取需要的信息
使用回调的写法
// 获取邀请码
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代码结构清晰很多。如果你对PromiseGenerator熟悉的话,有没有发现在Async中都有它们的身影,如在代码中同样需要用到Promise,再如最后执行代码那步有没有发现关键词asyncGenerator函数中的*awaitGenerator函数中的yeild关键词。

完整的代码实例请移步至 fetch-ss

© 2016 - 2021 BY 禾惠 粤ICP备20027042号