使用Node,Express和google Analytics API迷失了回调地狱

时间:2016-08-29 21:26:08

标签: javascript node.js asynchronous async-await

我是初学者,所以我会尝试以最好的方式揭露我的问题。我正在尝试在服务器端调用Google AnalyticsAPI,以在客户端使用react和d3显示一些数据。这是我调用GA api的脚本:

var google = require ("googleapis");
var key = require ('./client_id.json');

const VIEW_ID = 'ga:80820965';

let jwtClient = new google.auth.JWT(
  key.client_email, 
  null,
  key.private_key,
  ['https://www.googleapis.com/auth/analytics.readonly'],
  null
);

    jwtClient.authorize(function (err, tokens) {
      if (err) {
        console.log(err);
        return;
      }
      let analytics = google.analytics('v3');
        queryData(analytics);
    });

var queryData = function(analytics) {
      analytics.data.ga.get({
        'auth': jwtClient,
        'ids': VIEW_ID,
        'metrics': 'ga:uniquePageviews',
        'dimensions': 'ga:pagePath',
        'start-date': '30daysAgo',
        'end-date': 'yesterday',
        'sort': '-ga:uniquePageviews',
        'max-results': 10,
      }, function (err, response) {
        if (err) {
          console.log(err);
          return;
        }
        console.log(JSON.stringify(response, null, 4));
      });  
    }


module.exports = {
    queryData
};

当我独立调用这个脚本时,一切都很好,但是当我用我的整个项目调用它时,我遇到了以下错误:

[1]   analytics.data.ga.get({
[1]            ^
[1] 
[1] TypeError: Cannot read property 'data' of undefined

据我所知,data未定义,因为analytics未定义。并且analytics未定义,因为此调用:

   jwtClient.authorize(function (err, tokens) {
      if (err) {
        console.log(err);
        return;
      }
      let analytics = google.analytics('v3');
        data = queryData(analytics);
    });

是异步调用。我想是client_id加载的时间。

那么如何编写此脚本以便queryData仅在此部分运行时运行:

let analytics = google.analytics('v3');
        data = queryData(analytics);

准备好了吗?

我希望我的问题清楚明白,对你有意义。我读过有关async / await模块的信息。但是我不能自己使用它。

编辑#1:我需要使用类似的东西,但我不确定如何

module.exports = {queryData: function (err, req, res, next) { next(); }};

1 个答案:

答案 0 :(得分:3)

您在此处将analytics定义为本地变量:

jwtClient.authorize(function (err, tokens) {
  if (err) {
    console.log(err);
    return;
  }
  let analytics = google.analytics('v3');
    queryData(analytics);
});

然后期望它在导出中的queryData(analytics)处可用。

您可以做的是在承诺中解决您的authorize调用(因为首次初始化时会出现竞争条件,因此您可以将其包含在承诺中并等待它解决致电queryData)。像这样:

var google = require ("googleapis");
var key = require ('./client_id.json');
const Promise = require('bluebird');
var authorizationPromise;

const VIEW_ID = 'ga:80820965';

let jwtClient = new google.auth.JWT(
  key.client_email, 
  null,
  key.private_key,
  ['https://www.googleapis.com/auth/analytics.readonly'],
  null
);

authorizationPromise = Promise.promisify(jwtClient.authorize)()
.then(function (err, tokens) {
  if (err) {
    throw new Error(err);
  }

  return google.analytics('v3');
})
.catch(function(err) {
  console.log(err);
});

var queryData = function() {
  authorizationPromise.then(function(analytics) {
      analytics.data.ga.get({
        'auth': jwtClient,
        'ids': VIEW_ID,
        'metrics': 'ga:uniquePageviews',
        'dimensions': 'ga:pagePath',
        'start-date': '30daysAgo',
        'end-date': 'yesterday',
        'sort': '-ga:uniquePageviews',
        'max-results': 10,
      }, function (err, response) {
        if (err) {
          console.log(err);
          return;
        }
        console.log(JSON.stringify(response, null, 4));
      }); 
  });
};

module.exports = {
    queryData
};

我不确定jwtClient.authorize是否提供了承诺API,所以我只是使用bluebird“宣传”它。