node.js - Utilisez Node comme robot d'exploration pour simuler l'interface afin d'obtenir des données en boucle. Comment async/await peut-il réaliser des opérations synchrones et contrôler le processus ?
给我你的怀抱
给我你的怀抱 2017-07-06 10:36:31
0
4
1686

L'idée actuelle est la suivante : 1. Obtenez toutes les URL des pages de balises sous la catégorie, 2. Parcourez la page d'exploration pour récupérer la page de balises actuelle afin d'obtenir l'adresse API json, 3. Récupérez la liste de produits de la balise actuelle. , 4. Récupérez les produits en cours de chargement dans les pages à onglets.

Mais ce qui est fait maintenant, c'est qu'au début de la deuxième étape, il n'attend pas que 2-4 soit terminé avant de passer à la suivante. J'ai essayé d'utiliser async/await, mais le contrôle de processus n'a pas été implémenté. Demander conseil ici.

var http = require('http');
var fs = require("fs");
var superagent = require('superagent');
var urls = [];
var pageIndex = 1;
var xlsxData = '';

getGoodsUrl(urls);

function getGoodsUrl(urls){
    superagent
        .post('http://bravetime.davdian.com/index.php?c=Index&a=getCatNavList')
        .type('text/html; charset=utf-8')
        .set('Accept','application/json, text/javascript, */*; q=0.01')
        .end(function(err, res) {
            if (err) {
                console.log('分类数据请求失败');
            } else {
                console.log('分类数据请求成功');
                var resData = res.text;
                var resData = JSON.parse(resData); 
                if(resData.data.length > 0){
                    resData.data.forEach(function(item){
                        var rowObj = [];
                        var title = item.title;
                        var category = item.content.category;
                         category.forEach(function(item){
                             var text = [];
                             text.push(title+ '--' + item.text);
                             text.push(item.link);
                            rowObj.push(text);
                         });
                         urls.push(rowObj);
                     });
                     loopUrls(urls);
                } else {
                    console.log('分类数据为空');
                }

                // saveInfo(xlsxData);
            }
        })
}

function loopUrls(urls){
    urls.forEach(function(item){
        var row = item;
        row.forEach(function(item){
            var tagTitie = item[0];
            var tegUrl = item[1];
            getApiUrl(tagTitie,tegUrl);
        });
    });
}

function getApiUrl(title,url){
    var realUrl = 'http://bravetime.davdian.com' + url;
    http.get(realUrl,function(res){
         var html = '';
         res.on('data',function(data){
             html += data;
         });
         res.on('end',function(){
             console.log('正在获取' + title + '页面数据');
             var reg = /goodsUrl = "(.+)"/;
             var apiUrl = reg.exec(html);
             getGoodsJson(apiUrl[1],pageIndex);
         });
     }).on('error',function(){
         console.log('获取html出错!!');
     });
}

function getGoodsJson(url,pageIndex){
    superagent
        .post('http://bravetime.davdian.com/' + url + 'page_size=10&rp=catergory_search&rl=list')
        .send({page:pageIndex})
        .type('application/x-www-form-urlencoded; charset=UTF-8')
        .set('Accept','application/json, text/javascript, */*; q=0.01')
        .end(function(err, res) {
            if (err) {
                console.log('第' + pageIndex + '页请求失败');
            } else {
                console.log('第' + pageIndex + '页请求成功');
                var resData = res.text;
                var resData = JSON.parse(resData); 
                if(resData.data.length > 0){
                    resData.data.forEach(function(item){
                         xlsxData = xlsxData + item.goods_name + '  ' + item.shop_price + '  ' + item.goods_number + '\r\n';
                     });
                     pageIndex = parseInt(pageIndex) + 1;
                     setTimeout(function(){
                         getGoodsJson(url,pageIndex);
                     },200);
                } else {
                    console.log('数据已加载完毕');
                    saveTxt(xlsxData);
                    pageIndex = 1;
                    return false;
                }

                // saveInfo(xlsxData);
            }
        })

}

function saveTxt(data){
    fs.writeFile("create.txt",data,function (err) {
        if (err) throw err ;
         console.log("File Saved !"); //文件被保存
    }) ;
}
function saveInfo(data){
     var buffer = xlsx.build([{name: "mySheetName", data: data}]);
     fs.writeFileSync("myFile.xlsx", buffer, 'binary');
     console.log('excel保存成功');
}

Voici le diagramme de résultats et la séquence d'exécution du code :

给我你的怀抱
给我你的怀抱

répondre à tous(4)
Peter_Zhu

générateur
async
promesse

仅有的幸福

L'ensemble de votre processus est asynchrone et vous ne voyez aucune signification à la synchronisation. Je pense que vous ne comprenez peut-être pas ce qu'est l'asynchrone.

Async/await est basé sur Promise et Superagent lui-même prend en charge Promise. Vous pouvez utiliser async/await directement.

async function() {
  try {
    const result = await superagent.get(url);
    console.log(result.headers);
    console.log(result.body);
  } catch (error) {
    console.error(error);
  }
}

http://visionmedia.github.io/...

http://www.ruanyifeng.com/blo...

Ensuite, il ne vous reste plus qu'à mettre http.get() 换成 superagent.get().

習慣沉默

En général, les gens n’ont pas la patience de lire la logique métier des autres.

Comme mentionné ci-dessus, Async/await est basé sur Promise. Si l'interface API de la bibliothèque tierce que vous appelez ne renvoie pas d'objet de promesse, si vous souhaitez utiliser Async/await, vous ne pouvez créer un nouvel objet de promesse que sur à chaque étape. C'est en fait très difficile à écrire. Bien sûr, ce serait très pratique s'il pouvait renvoyer un objet promis.

Ce qui suit est écrit en utilisant l'événement du module core du nœud sans promesses, pour votre référence :

const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();

myEmitter.on('step1', (m) => {
    //第一步
    //业务逻辑处理得到结果result1
        
    //判断是否触发下一步,如有需要将这步的结果传给下一步
    myEmitter.emit('step2', result1);
   
});
myEmitter.on('step2', (result1) => {
    //第二步
    //业务逻辑处理得到结果result2
        
    //判断是否触发下一步,如有需要将这步的结果传给下一步
    myEmitter.emit('step3', result2);
});
myEmitter.on('step3', (result2) => {
    //以此类推
});
myEmitter.emit('step1', urls);
刘奇

Peut utiliser Node8 util.promisify , ou Bluebird, etc. changez la fonction de style de rappel Node en une fonction de style Promise, puis vous pouvez utiliser async/await pour écrire du code.

Le code lui-même est toujours un appel asynchrone, mais la méthode d'écriture semble synchrone. Par conséquent, vous devez toujours faire attention à la structure du processus lors de l’écriture, en particulier lors de l’écriture de boucles. Le code est trop long, j'ai donc écrit un petit exemple pour illustrer

async function remoteCall() {
    // do something
}

list = [];  // 假设是很多数据


async function process() {
    // 这种写法必须要一个 remoteCall 完成之后才进行另一个
    for (let i = 0; i < list.length; i++) {
        await remoteCall();
    }

    doAfter();
}

async function process2() {
    // 这种写法没法 await
    list.forEach(function(t) {
        remoteCall();
    });
}

async function process3() {
    // 这种写法 doAfter 一早就会执行
    list.forEach(async function(t) {
        await remoteCall();
    });

    // 它可能会在 remoteCall() 之前
    doAfter();
}

async function process4() {
    // 这种写法必须要全部 remoteCall 成功才能进行到 doAfter
    // remoteCall返回的 promise 如果 reject 会抛异常
    var promises = list.map(t => remoteCall());
    await Promise.all(promises);
    doAfter();
}
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal