การเข้าถึงที่อยู่ติดต่อของ Google เมื่อผู้ใช้ลงชื่อเข้าใช้ทำให้เกิดข้อผิดพลาด Meteor.bindEnvironment เกิดอะไรขึ้นกับความเข้าใจของฉันเกี่ยวกับเส้นใยที่นี่

คำตอบใน - "เกิดอะไรขึ้นกับ Meteor และ Fibers/bindEnvironment() ?" มีประโยชน์มาก แต่ก็ไม่สามารถช่วยฉันแก้ไขปัญหาได้

นี่คือสิ่งที่ฉันทำ:

  1. เข้าสู่ระบบด้วย Google
  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

นี่ไม่ใช่วิธีที่ถูกต้องในการทำ async ใน JavaScript:

  • SocialFunGoogle ไปถึง // A ก่อนที่โค้ดที่ // B จะทำงาน ดังนั้นจึงไม่มีการรับประกันว่า gcontacts.token ได้รับการตั้งค่าแล้ว (นั่นอาจเป็นสาเหตุของการหมดเวลา แต่นั่นก็ไม่น่าเชื่อถือตั้งแต่นั้นเป็นต้นมา ฟังก์ชันจะล้มเหลวอย่างลึกลับ หากการรีเฟรชโทเค็นใช้เวลานานกว่า 500 มิลลิวินาที)
  • return ที่ // C ส่งกลับจากฟังก์ชันโทรกลับแบบไม่ระบุชื่อ ไม่ใช่จาก SocialFunGoogle ดังนั้นการดำเนินการนี้จะไม่เป็นไปตามที่คุณต้องการ

โดยปกติคุณจะต้องซ้อนฟังก์ชันที่เหลือของคุณไว้ในคอลแบ็กนี้ แต่ Meteor ใช้ Fibers ดังนั้นคุณไม่จำเป็นต้องทำ Fibers ช่วยให้คุณเขียนโค้ดได้เหมือนกับว่ามันเป็นแบบซิงโครนัส แต่เบื้องหลังมันยังคงทำงานแบบอะซิงโครนัสเหมือนกับแอปพลิเคชัน node.js อื่นๆ

น่าเสียดายที่แพ็คเกจ npm ส่วนใหญ่เขียนขึ้นสำหรับรูปแบบการโทรกลับ แต่มีวิธีง่ายๆ ในการปรับโค้ดการโทรกลับสำหรับ Fibers ฉันจะใช้ฟิวเจอร์ส ต่อไปนี้คือวิธีที่คุณสามารถเขียนโค้ดนั้นใหม่โดยใช้ 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. การดำเนินการแบบอะซิงโครนัสเสร็จสิ้น ในการเรียกกลับสำหรับการดำเนินการแบบอะซิงก์นั้น เราจะแก้ไขอนาคตโดยใช้วิธี return
  5. เมื่ออนาคตได้รับการแก้ไข Fiber ก็ตื่นขึ้น และวัตถุที่เราส่งผ่านไปยัง future.return ก็ปรากฏออกมาจาก future.wait
  6. ฟังก์ชันดำเนินไปตามปกติ

คุณสามารถใช้รูปแบบนี้เพื่อจัดการกับการโทร getContacts ได้เช่นกัน เนื่องจากโค้ดเดียวที่ทำงานนอก Fiber คือการเรียก future.return คุณจึงไม่จำเป็นต้อง bindEnvironment หรือสร้าง Fiber ของคุณเอง

person user3374348    schedule 23.05.2014