【问题标题】:Firebase: Using the newly created key in the success callbackFirebase:在成功回调中使用新创建的密钥
【发布时间】:2016-02-07 07:34:10
【问题描述】:

当推送事件发生时,它会返回一个新的密钥。

例如来自Docs:

// Generate a reference to a new location and add some data using push()
var newPostRef = postsRef.push();

// Get the unique ID generated by push()
var postID = newPostRef.key();

我想做的事:

现在我想在之后直接使用这个键来改变数据库的另一部分。

但由于 JavaScript 的异步特性,我被绊倒了。

我已经尝试了成功回调:

var newMessageIDRef =  firebaseMessagesRef.push({
  authorName: 'Nick',
  text:"Hello!"
},printKey(newMessageIDRef));

var printKey = function(newMessageIDRef) {
  console.log(newMessageIDRef);//undefined
}

(我假设在设置 newMessageIDRef 之前调用了 printKey)

我尝试过使用“then”:

var newMessageIDRef =  firebaseConvosRef.push({
    authorName: 'Nick',
    text:"Hello!",
}).then(printKey(newMessageIDRef));

var printKey = function(newMessageIDRef) {
  console.log(newMessageIDRef);//undefined
}

(我假设括号导致printKey 立即执行,这让我想知道如何添加参数但不会导致提前执行)

问题:

是否有一些传统的方法来处理如此常见的事情,或者我最好的解决方案是使用Promise 并使用resolve 处理密钥?

更新(虽然还没有回答):

下面的工作,但它没有意义。

var printKey = function(newMessageIDRef) {
    console.log(newMessageIDRef);//undefined
}

var newMessageIDRef =  firebaseConvosRef.push({
    authorName: 'Nick',
    text:"Hello!",
});
printKey(newMessageIDRef)

我认为 newMessageIDRef 不一定会在调用 printKey 时返回。

【问题讨论】:

  • 为什么要记录字符串而不是变量?
  • @Bergi 这只是制作 sn-p 的意外,感谢您指出!

标签: javascript asynchronous callback firebase promise


【解决方案1】:

push 和 then 都期望回调 函数 作为它们的参数。您将不得不传递 printKey 本身,而不是调用它(用什么?!)并传递它的结果。应该是

function printKey(newMessageIDRef) {
  console.log(newMessageIDRef);
}
firebaseConvosRef.push({
    authorName: 'Nick',
    text:"Hello!",
}).then(printKey);
//      ^^^^^^^^

【讨论】:

    【解决方案2】:

    根据the documentation,.push()工作如下:

    • 返回“生成位置的 Firebase 引用”
    • 接受作为第二个参数的回调函数,“将在指定值同步到 Firebase 服务器时调用”。回调接受一个参数,如果发生错误则为错误对象,否则为null。

    因此,为了在回调中使用返回的引用,它必须被赋值,然后被回调作为外部变量访问。

    var newMessageIDRef = firebaseMessagesRef.push({
        authorName: 'Nick',
        text:"Hello!"
    }, printKey);
    
    var printKey = function(err) {
        if(!err) {
            console.log(newMessageIDRef);
        }
    }
    

    或者,您可以使用(至少)两个 Firebase 承诺者中的一个来承诺,这两者看起来都很好,但目前在文档中缺少他们承诺的.push() 的具体示例:

    Fireproof

    这是关于它如何工作的有根据的猜测:

    var fireproofMessagesRef = new Fireproof(firebaseMessagesRef);
    
    fireproofMessagesRef.push({
        authorName: 'Nick',
        text:"Hello!"
    }).then(successHandler, errorHandler);
    
    function successHandler(childIDRef) {
        console.log(childIDRef);
    }
    function errorHandler(err) {
        console.error(err);
    }
    

    Firebase-promisified

    再次,有根据的猜测:

    // having promisified Firebase.
    firebaseMessagesRef.promisePush({
        authorName: 'Nick',
        text:"Hello!"
    }).then(successHandler, errorHandler);
    
    function successHandler(childIDRef) {
        console.log(childIDRef);
    }
    function errorHandler(err) {
        console.error(err);
    }
    

    我在这两种情况下的主要不确定性是childIdRef 是否作为参数出现在成功处理程序中,这看起来很合理,但我找不到确认。

    【讨论】:

      【解决方案3】:

      Firebase JavaScript SDK 不公开任何承诺,因此没有then()。相反,它基于回调工作。

      除此之外,我不完全确定您要完成什么。所以我只给出一些常见的sn-ps,希望其中一个能有所帮助。

      Firebase 的 push() 操作是纯客户端操作。它不会往返于服务器,而是在客户端生成一个统计上唯一的 ID。

      现在让我们假设您要创建一个新帖子(在 /posts/$postid 下)并将该新帖子的链接添加到数据库的另一个位置(例如 /users/$uid/posts/$postid):

      // Generate a reference to a new location and add some data using push()
      var newPostRef = postsRef.push();
      
      // Get the unique ID generated by push()
      var postID = newPostRef.key();
      
      // ref is a reference to the root, uid is the id of the current user
      var userRef = ref.child('users').child(uid);
      
      // Write the post to Firebase
      newPostRef.set({ title: 'Firebase: Using the newly created key...', uid: uid }, function(newRef) {
          userRef.child('posts').child(postID).set(true);
      });
      

      你会注意到我没有在回调中使用newRef。因为我已经知道postID 是什么。

      上述方法将对 Firebase 执行两次写入操作:

      1. 实际帖子
      2. 用户个人资料中帖子的链接

      自 Firebase 2.4(适用于 JavaScript,2.3 适用于 Android 和 iOS)以来,可以将两个写入作为单个操作执行。这再次利用了我们可以“预先计算”post-ID 作为客户端push() 操作的事实:

      var ref = new Firebase('https://your-app.firebaseio.com');
      var postsRef = ref.child('posts');
      
      // Get a unique ID generated by push()
      var postID = postsRef.push().key();
      
      // Create a single object, where we'll put all updates
      var updates = {};
      
      // We'll put the post into /posts/$postId
      updates['/posts/'+postID] = { title: 'Firebase: Using the newly created key...', uid: uid };
      
      // Put the postId under /users/$uid/posts/$postId
      updates['/users/'+uid+'/posts/'+postID] = true;
      
      // Now write to both locations in one "big" swoop:    
      ref.update(updates);
      

      阅读更多内容:

      【讨论】:

      • 推送“是纯粹的客户端操作。它不会像@FrankvanPuffelen 所说的那样执行往返”这一事实更能说明问题。在成功回调中未定义或使用“then”使我相信存在导致问题的异步问题。
      • 现在唯一的问题是,在第一次写操作失败的情况下,如何回滚第二次写操作?
      • 或者扇出策略是否涵盖了其中一次写入失败的情况?
      • 我提供的第二种解决方案将单个命令发送到 Firebase 服务器。所以不需要回滚。
      猜你喜欢
      • 2016-12-05
      • 2017-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-27
      • 2021-10-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多