2017-10-05 3 views
0

Je travaille sur un projet Node qui utilise principalement Express et Request pour présenter les statistiques d'un point de terminaison API particulier.La fonction primaire continue pendant qu'un composant essentiel est encore généré. Comment est-ce que je fais attendre la fonction?

Je suis tombé sur un problème quand une requête POST est faite à un certain itinéraire.

Résultat souhaité: Le serveur envoie une requête à un point de terminaison API Overwatch et renvoie la réponse de l'API à la route/recherche. Résultat réel: Le serveur envoie une requête à un point de terminaison API Overwatch, Node procède à la fin de la fonction appelée sans terminer la requête, laissant la réponse "indéfinie".

Voici le fichier app.js que j'ai, et le résultat de la console pour l'accompagner.

//Load npm modules 
const express = require('express'); 
const bodyParser = require('body-parser'); 
const request = require('request'); 

//Set obj 'app' to express(); 
const app = express(); 

app.use(bodyParser.urlencoded({ extended: false})); 

app.set('view engine', 'pug'); 

app.get('/', (req, res, next) => { 
    res.render('index'); 
}); 

app.post('/lookup', (req, res, next) => { 
    const battletag = req.body.battletag; 
    console.log("running"); 
    var stats = lookupStats(battletag); 
    console.log("lookupStats() completed. Attempting to render stats."); 
    res.render(stats); 
}); 

app.listen(3000,() => { 
    console.log('The application is running on localhost:3000!') 
}); 


function apiRequestObj(battletag) { 
    var requestObj = { 
     uri: "https://owapi.net/api/v3/u/" + battletag + "/blob?platform=pc", 
     timeout: 10000, 
     headers: { 
      'User-Agent': 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31' 
     } 
    } 
    return requestObj; 
} 

function apiRequest(requestObj) { 
    request(requestObj, function(err, res, body) { 
     if (err) { 
      return "Error: " + err; 
     } else { 
      var result = JSON.parse(body); 
      result = result.us.stats.competitive.overall_stats; 
      console.log(result); 
      return result; 
     } 
    }); 
} 

function lookupStats(battletag) { 
    battletag = battletag.replace('#', '-'); 
    console.log("Searching Battletag: " + battletag); 
    var requestObj = apiRequestObj(battletag); 
    var apiResult = apiRequest(requestObj); 
    console.log(apiResult); 
    return apiResult; 
} 

The application is running on localhost:3000! 
running 
Searching Battletag: Unreal-11505 
undefined 
lookupStats() completed. Attempting to render stats. 
TypeError: Path must be a string. Received undefined 
    at assertPath (path.js:7:11) 
    at extname (path.js:1431:5) 
    at new View (/Users/neil/Dropbox/Programming/Web Development/owapi/node_modules/express/lib/view.js:56:14) 
    at EventEmitter.render (/Users/neil/Dropbox/Programming/Web Development/owapi/node_modules/express/lib/application.js:570:12) 
    at ServerResponse.render (/Users/neil/Dropbox/Programming/Web Development/owapi/node_modules/express/lib/response.js:1008:7) 
    at app.post (/Users/neil/Dropbox/Programming/Web Development/owapi/app.js:22:9) 
    at Layer.handle [as handle_request] (/Users/neil/Dropbox/Programming/Web Development/owapi/node_modules/express/lib/router/layer.js:95:5) 
    at next (/Users/neil/Dropbox/Programming/Web Development/owapi/node_modules/express/lib/router/route.js:137:13) 
    at Route.dispatch (/Users/neil/Dropbox/Programming/Web Development/owapi/node_modules/express/lib/router/route.js:112:3) 
    at Layer.handle [as handle_request] (/Users/neil/Dropbox/Programming/Web Development/owapi/node_modules/express/lib/router/layer.js:95:5) 
{ level: 61, 
    comprank: 2031, 
    games: 116, 
    win_rate: 53.21, 
    losses: 51, 
    rank_image: 'https://d1u1mce87gyfbn.cloudfront.net/game/playerlevelrewards/0x0250000000000928_Border.png', 
    wins: 58, 
    ties: 7, 
    prestige: 1, 
    avatar: 'https://d1u1mce87gyfbn.cloudfront.net/game/unlocks/0x02500000000002F7.png', 
    tier: 'gold' } 

Est-ce que quelqu'un a une idée de comment je peux faire Node attendre la réponse du critère d'évaluation de l'API avant de poursuivre?

Répondre

0

Vous devez transmettre une fonction de rappel à la fonction asynchrone, puis appeler la fonction callback. Tout ce qui doit être fait après que la demande est terminée, devrait être fait dans le rappel.

function apiRequest(requestObj, callback) { 
    request(requestObj, function(err, res, body) { 
    if (err) { 
     return callback(err); 
    } else { 
     var result = JSON.parse(body); 
     result = result.us.stats.competitive.overall_stats; 
     console.log(result); 
     return callback(null, result); 
    } 
    }); 
} 

function lookupStats(battletag) { 
    battletag = battletag.replace('#', '-'); 
    console.log("Searching Battletag: " + battletag); 
    var requestObj = apiRequestObj(battletag); 
    apiRequest(requestObj, function (err, result) { 
    if (err) return console.error("error: ", err); 
    return console.log("result: ", result); 
    }); 
} 

De même, si lookupStats être appelé de quelque part, devrait également accepter un rappel et appelle ensuite la fonction de rappel lorsque la demande est terminée.