Доступ к контактам Google при входе пользователя вызывает ошибку Meteor.bindEnvironment. Что не так с моим пониманием волокон здесь?

Ответ в - "Что происходит с Meteor и Fibers/bindEnvironment() ?" очень полезен, однако не может помочь мне решить мою проблему.

Вот что я делаю:

  1. Войти через гугл
  2. Вызов FunGoogle (пользователь) из Accounts.onCreateUser

код:

SocialFunGoogle = function (user) {
  var config = Accounts.loginServiceConfiguration.findOne({service: 'google'});

  var opts = {
    consumerKey: config.clientId,
    consumerSecret: config.secret,
    token: user.services.google.accessToken,
    refreshToken: user.services.google.refreshToken
  };
  var gcontacts = new GoogleContacts(opts);

  gcontacts.refreshAccessToken(opts.refreshToken, function (err, accessToken) {
    if (err && err != null) {
      console.log('gcontact.refreshToken, ', err);
      return false;
    } else {
      console.log('gcontact.access token success!');
      gcontacts.token = accessToken;
    }
  });

  var fn = Meteor.bindEnvironment(function () {
    var Fiber = Meteor.require('fibers');
    var Future = Meteor.require('fibers/future');
    var future = new Future();
    setTimeout(function () {
      return future.return(
        Fiber(function () {
          gcontacts.getContacts(
            function (err, contact) {
              contact = [{
                name: 'S Sharma',
                email: '[email protected]',
                photoUrl: 'https://www.google.com/m8/feeds/photos/media/procrazium%40gmail.com/adf456aaaabbnndaa',
                mime_type: 'image/*'
              }, {
                name: 'A Kapil',
                email: '[email protected]',
                photoUrl: 'https://www.google.com/m8/feeds/photos/media/procrazium%40gmail.com/22aaaab555758bc37952',
                mime_type: 'image/*'
              }, {
                name: 'A Kartik',
                email: '[email protected]',
                photoUrl: 'https://www.google.com/m8/feeds/photos/media/procrazium%40gmail.com/2f2aaa02aab00f7aa85a2',
                mime_type: 'image/*'
              }];

              contact.map(function (c) {
                SocialConnect.insert(c);
              });

              return contact;
            });
        }).run()
      );
    }, 500);
  });

  fn();
}

Когда я пытаюсь войти в систему, мой код выдает следующие ошибки.

  1. Исключение при вызове метода «логин» TypeError: невозможно установить свойство «_meteor_dynamics» неопределенного

  2. Ошибка: код Meteor всегда должен выполняться внутри волокна. Попробуйте обернуть обратные вызовы, которые вы передаете в библиотеки, отличные от Meteor, с помощью Meteor.bindEnvironment.

Не могли бы вы указать, что я делаю неправильно?


person procrazium    schedule 22.05.2014    source источник


Ответы (1)


gcontacts.refreshAccessToken(opts.refreshToken, function (err, accessToken) {
  // B
  if (err && err != null) {
    console.log('gcontact.refreshToken, ', err);
    return false; // C
  } else {
    console.log('gcontact.access token success!');
    gcontacts.token = accessToken;
  }
});
// A

Это неправильный способ сделать асинхронность в JavaScript:

  • SocialFunGoogle достигает // A до того, как выполнится код в // B, поэтому нет гарантии, что gcontacts.token был установлен. (Вероятно, для этого и предназначен тайм-аут, но это ненадежно, поскольку в этом случае функция загадочным образом завершится ошибкой, если обновление токена займет более 500 мс.)
  • return в // C возвращается из анонимной функции обратного вызова, а не из SocialFunGoogle, поэтому это не будет делать то, что вы хотите.

Обычно вам нужно было бы вложить остальную часть вашей функции в этот обратный вызов, но Meteor использует Fibers, поэтому вам не нужно этого делать. Fibers позволяет вам писать код так, как если бы он был синхронным, но за кулисами он по-прежнему работает асинхронно, как и любое другое приложение node.js.

К сожалению, большинство пакетов npm написаны для стиля обратного вызова, но есть простые способы адаптировать код обратного вызова для волокон. Я буду использовать фьючерсы. Вот как вы можете переписать этот код с помощью Futures:

var future = new Future(); // 1

gcontacts.refreshAccessToken(opts.refreshToken, function (err, accessToken) { //2
  future["return"]({err: err, accessToken: accessToken}); // 4
});

var result = future.wait(); // 3, 5
if (result.err && result.err != null) { // 6
  console.log('gcontact.refreshToken, ', result.err);
  return false;
} else {
  console.log('gcontact.access token success!');
  gcontacts.token = result.accessToken;
}

Вот как это выполняется:

  1. Мы создаем новое, нерешенное Будущее.
  2. Мы запускаем асинхронное действие.
  3. Пока асинхронное действие все еще происходит, мы wait() в будущем. Текущее волокно засыпает, ожидая разрешения Будущего.
  4. Асинхронное действие завершено. В обратном вызове для этого асинхронного действия мы разрешаем Future, используя его метод return.
  5. Поскольку Будущее разрешено, Волокно просыпается, и объект, который мы передали в future.return, появляется из future.wait.
  6. Функция продолжается в обычном режиме.

Вы также можете использовать этот шаблон для работы с вызовом getContacts. Поскольку единственным кодом, который выполняется за пределами Fiber, являются вызовы future.return, вам никогда не нужно bindEnvironment или создавать свой собственный Fiber.

person user3374348    schedule 23.05.2014