且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

真的很困惑:如何在云代码中正确使用解析承诺

更新时间:2022-11-16 16:16:04

我自己解决了!!

问题是,正如错误明确指出的那样,我的方法updateUsernameForAccountId没有返回Promise对象.但是,问题出在updateUsernameForMessagesSentByAccountIdupdateUsernameForMessagesReceivedByAccountId之内,因为执行query.find()是异步方法,因此不会立即返回其完成处理程序中的任何内容.

要使函数返回Promise,您必须return Promise.

所以答案是要确保return query.find().

Instead of nesting various functions within success completion handlers, I'd like to separate out my functions so that they can either be used independently or in succession. However, I'm super confused regarding the syntax of promises in Parse and have not been able to chain them together successfully despite looking at many other *** answers (e.g., here, here, here, and here) and Parse's official documentation, overview, and blog post about the topic.

Here's an example of my Cloud Code where I am trying to use chained promises:

Parse.Cloud.beforeSave(Parse.User, function(request, response) {
    var account = request.object;
    if (account.existed()) {
        if (account.dirtyKeys().indexOf("username") >= 0) {
            updateUsernameForAccountId(account.get("username"), account.id)
                .then(
                    function() {
                        console.log("Checkpoint SUCCESS");
                        response.success();
                    }, function(error) {
                        console.log("Checkpoint ERROR");
                        response.error(error);
                    });
        }
    }
});

function updateUsernameForAccountId(username, accountId) {
    console.log("Checkpoint A-1 ("+username+", "+accountId+")");
    updateUsernameForMessagesSentByAccountId(username, accountId)
        .then(
            function() {
                console.log("Checkpoint A-2");
                return updateUsernameForMessagesReceivedByAccountId(username, accountId);
            })
        .then(
            function() {
                console.log("Checkpoint A-3");
                return Parse.Promise.as();
            }, function(error) {
                console.log("Checkpoint A-ERROR");
                return Parse.Promise.error(error);
            });
};

function updateUsernameForMessagesSentByAccountId(username, accountId) {
    console.log("Checkpoint B-1");
    var query = new Parse.Query(parseClassMessage);
    query.equalTo(parseKeySenderId, accountId);
    query.find()
        .then(
            function(results) {
                console.log("Checkpoint B-2");
                var object;
                for (var i = 0; i < results.length; i++) {
                    console.log("Checkpoint B-2-"+i);
                    object = results[i];
                    object.set(parseKeySenderUsername, username);
                }
                return Parse.Promise.as(results);
            })
        .then(
            function(objects) {
                console.log("Checkpoint B-3");
                return Parse.Object.saveAll(objects);
            })
        .then(
            function() {
                console.log("Checkpoint B-4");
                return Parse.Promise.as();
            }, function(error) {
                console.log("Checkpoint B-ERROR");
                return Parse.Promise.error(error);
            });
};

function updateUsernameForMessagesReceivedByAccountId(username, accountId) {
    console.log("Checkpoint C-1");
    var query = new Parse.Query(parseClassMessage);
    query.equalTo(parseKeyRecipientId, accountId);
    query.find()
        .then(
            function(results) {
                console.log("Checkpoint C-2");
                var object;
                for (var i = 0; i < results.length; i++) {
                    console.log("Checkpoint C-2-"+i);
                    object = results[i];
                    object.set(parseKeyRecipientUsername, username);
                }
                return Parse.Promise.as(results);
            })
        .then(
            function(objects) {
                console.log("Checkpoint C-3");
                return Parse.Object.saveAll(objects);
            })
        .then(
            function() {
                console.log("Checkpoint C-4");
                return Parse.Promise.as();
            }, function(error) {
                console.log("Checkpoint C-ERROR");
                return Parse.Promise.error(error);
            });
};

The expected behavior is:

  • Right before saving a User object, check if it is an already existing User (v. a newly created User) and whether the username was changed.
  • IF YES: Perform function updateUsernameForAccountId(username, accountId), which performs updateUsernameForMessagesSentByAccountId(username, accountId) and then updateUsernameForMessagesReceivedByAccountId(username, accountId).
    • N.b. I don't need these two methods to be synchronous, but I thought it necessary in order to return a single Promise object back to beforeSave.

I am able to upload this code to Cloud Code successfully, but when I go into the data browser on Parse.com and change the username of an existing User object to test, the log produces the following output:

E2015-08-11T21:16:23.467Z]v27 before_save triggered for _User as master:
  Input: {"original":{"createdAt":"2015-08-09T16:53:47.194Z","objectId":"mkTluyGbHf","updatedAt":"2015-08-11T17:23:19.523Z","username":"oldname@example.com"},"update":{"username":"newname@example.com"}}
  Result: TypeError: Cannot call method 'then' of undefined
    at updateUsernameForAccountId (main.js:114:4)
    at main.js:16:4
I2015-08-11T21:16:23.533Z]Checkpoint A-1 (newname@example.com, mkTluyGbHf)
I2015-08-11T21:16:23.534Z]Checkpoint B-1

And I also receive the following error in the Parse.com data browser:

Error: TypeError: Cannot call method 'then' of undefined at updateUsernameForAccountId (main.js:114:4) at main.js:16:4

Please let me know what additional information or clarification I can provide. I apologize in advance that I am not able to articulate my question, errors, or confusions more clearly.

I solved it myself!!

The issue was that, as the error clearly stated, my method updateUsernameForAccountId wasn't returning a Promise object. However, the issue was within updateUsernameForMessagesSentByAccountId and updateUsernameForMessagesReceivedByAccountId, as executing query.find() is an asynchronous method and so will not return whatever is in its completion handler immediately.

In order for a function to return a Promise...you must return a Promise.

And so the answer was to make sure to return query.find().