2017-05-04 55 views
1

我想調用Google Maps API並使用結果調用另一個API(這是我的最終目標,現在我只想將結果打印到控制檯)。我的問題是,承諾在API調用之前解決,並最終導致未定義的結果。在異步操作完成之前解決Promise

routes.js

const express = require('express'); 
const router = express.Router(); 
const geospacial = require('./geospacial.js'); 
const trailapi = require('./trailapi.js'); 

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

router.post('/', (req, res, next) => { 
    let activity = req.body.activity; 
    let radius = req.body.radius; 

    let getUserCoords = new Promise((resolve,reject) => { 
    let userCoords = geospacial.getCoords(req.body.zip); 
    resolve(userCoords); 
    }); 

    getUserCoords.then((result) => { 
    console.log("data: " + result); 
    }); 
}); 
module.exports = router; 

的谷歌地圖API(geospacial.js)

const https = require('https'); 
require('./env.js'); // comment out for production 

// Source: https://gist.github.com/clauswitt/1604972 
const getDistance = (start, end) => { 
    const earthRadius = 6371.008; 
    let lat1 = parseFloat(start.latitude); 
    let lat2 = parseFloat(end.latitude); 
    let lon1 = parseFloat(start.longitude); 
    let lon2 = parseFloat(end.longitude); 

    let dLat = (lat2 - lat1) * Math.PI/180; 
    let dLon = (lon2 - lon1) * Math.PI/180; 
    lat1 = lat1 * Math.PI/180; 
    lat2 = lat2 * Math.PI/180; 

    let a = Math.sin(dLat/2) * Math.sin(dLat/2) + 
      Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); 
    let c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); 
    let d = earthRadius * c; 
    let kilometers = Math.round(d * Math.pow(10, 2))/Math.pow(10, 2); 
    let miles = Math.round(kilometers * .621371); 
    console.log(miles); 
    return miles; 
}; 

// getDistance({latitude: 39.72122192, longitude: -80.51956177},{latitude: 40.02198029, longitude: -79.90330505}); // for testing 

const getCoords = (addressData) => { 
    let body = ''; 
    let req = https.get('https://maps.googleapis.com/maps/api/geocode/json?address=' + addressData + '&key=' + process.env.googleAPIKey, function(res) { 
    res.on('data', function(data) { 
     body += data; 
    }); 
    res.on('end', function() { 
     let result = JSON.parse(body); 
     let coords = result.results[0].geometry.location; 
     console.log(coords); 
     return coords; 
    }); 
    }); 

    req.on('error', function(e) { 
    console.error(e); 
    }); 
}; 
// getCoords('15351'); // for testing 

module.exports = { 
    getCoords: getCoords, 
    getDistance: getDistance 
}; 
+0

'new Promise'應該在'getCoords'中完成,而不是'getUserCoords'。異步回調中的'return'不起作用。 – Bergi

回答

2

getCoords有一個異步調用,這樣你就解決承諾getCoords返回一個值之前。您需要解決異步函數回調中的承諾。

let getUserCoords = geospacial.getCoords(req.body.zip);

const getCoords = (addressData) => { 
    // getCoords returns a promise 
    return new Promise(function(resolve, reject) { 
    let body = ''; 
    let req = https.get('https://maps.googleapis.com/maps/api/geocode/json?address=' + addressData + '&key=' + process.env.googleAPIKey, function(res) { 
    res.on('data', function(data) { 
     body += data; 
    }); 
    res.on('end', function() { 
     let result = JSON.parse(body); 
     let coords = result.results[0].geometry.location; 
     console.log(coords); 
     resolve(coords); // promise resolves inside the callback of your async function 
    }); 
    req.on('error', function(e) { 
     reject(e); 
     console.error(e); 
    }); 
    }); 
}) 
}; 


// getUserCoords now holds the returned promise and will fire .then() when the promise is resolved 
getUserCoords.then(function(coords) { 
    console.log(coords); 
}); 
+1

您在安裝錯誤處理程序之前'返回'。最好將它放在承諾執行程序回調中,並在發生時拒絕。 – Bergi

+0

哎呀,錯字好抓會編輯 –

+0

這正是我所需要的。謝謝!我仍然試圖將我的頭圍繞承諾。 – SmellydogCoding

1

什麼getCoords不返回一個承諾,所以這是行不通的。 也許你可以這樣改:

const getCoords = (addressData) => { 
    return new Promise((resolve, reject) => { 
     let body = ''; 
     let req = https.get('https://maps.googleapis.com/maps/api/geocode/json?address=' + addressData + '&key=' + process.env.googleAPIKey, function(res) { 
     res.on('data', function(data) { 
      body += data; 
     }); 
     res.on('end', function() { 
      let result = JSON.parse(body); 
      let coords = result.results[0].geometry.location; 
      console.log(coords); 
      resolve(coords); 
     }); 
     }); 

     req.on('error', function(e) { 
     console.error(e); 
     reject(e) 
     }); 

    }) 

}; 
1

getCoords功能有一個缺陷:它永遠不會返回任何東西。永遠。

https.get是異步的,並且req.on也是異步的。因此,您在getCoords中執行了兩個異步操作,但不會返回任何內容。

可能認爲在'end'事件處理程序return語句返回getCoords,但事實並非如此。位於事件處理程序中的返回返回事件處理程序函數(該函數在「res.on('end',」之後開始)。

不用擔心,你走在正確的軌道上;使用Promise

const getCoords = (addressData) => { 
    return new Promise((resolve, reject) => { 
    // do your stuff 
    // when you want to return a value, resolve: 
    resolve(apiResponse); 
    }); 
}; 

現在getCoords會返回一個Promise!

您的代碼打印出它的響應應該看起來有點像現在這樣:

geospacial.getCoords(req.body.zip).then((result) => { 
    console.log("data: " + result); 
}); 

其中

  1. 呼叫geospacial.getCoords
  2. 調用導致Promisethen
  3. (最終)解決並打印出你的結果!