【问题标题】:Parse cloud function - code ot executed in sequence解析云函数 - 代码未按顺序执行
【发布时间】:2018-02-01 11:30:50
【问题描述】:

如果满足某些条件,我有以下函数来更新行,并且在 for 循环结束时,响应包括更新的行数。尽管更新的行数超过零,但响应显示为零。查看日志,似乎 reponse.success() 在完成 for 循环之前触发。

为什么会这样?

Parse.Cloud.define("reset", function(request, response) {


    var isSaveNeeded = false
  var Query = new Parse.Query("price");
  Query.equalTo('isActive', true);
  Query.find({useMasterKey:true})
      .then((results) => {
        console.log("Found " + results.length + " price rows")
        var currentDate = moment()
        var noOfRowsUpdated = 0
        for (let i = 0; i < results.length; ++i) {
            var valid_till_date = results[i].get('valid_till_date');

            if (valid_till_date == null) {
                // if user had not selected valid_till_date then set to expire after system max no of days
                var updatedAt = results[i].get('updatedAt');
                if (currentDate.diff(updatedAt,'days') > 10) {
                  console.log("Permanent change row to be set inactive. Updated at - " + currentDate.diff(updatedAt)+ updatedAt)
                    results[i].set('isActive',false)
                    isSaveNeeded = true
                }
            } else if (currentDate.diff(valid_till_date) > 0) {
                // check whether valid_till_date has passed
                console.log("Found row with elapsed valid date "  + results[i].id)
                results[i].set("isActive",false)
                isSaveNeeded = true
            }
            if (isSaveNeeded == true) {
              console.log("Record needs to be saved for " + results[i].id)
              results[i].save(null, {useMasterKey:true})
                .then(function (user) {
                    ++noOfRowsUpdated
                    console.log("reset : Object ID: " + results[i].id + " saved - " + noOfRowsUpdated)
                  })
                .catch(function (error) {
                    console.log("reset : Error saving Object ID: " + results[i].id + error);
                    response.error(error);
                })
            } else {

              console.log("Record not to be saved for " + results[i].id)
            }
            isSaveNeeded = false
        } // end of for loop
        //BELOW IS EXECUTED BEFORE FOR LOOP COMPLETES
        console.log("Updated " + noOfRowsUpdated +" price rows");
        response.success("Updated " + noOfRowsUpdated +" price rows")
      }) // end of .then((results) 
      .catch(function(error) {
        response.error("Failed to fetch from price" + error );
      });
});

【问题讨论】:

    标签: javascript parse-platform parse-javascript-sdk parse-cloud-code


    【解决方案1】:

    Parse.com 的 save 异步运行,因此循环在保存发生之前完成。解决方案是稍微重新组织一下代码,并在执行响应函数之前等待保存。

    诀窍是将每次保存返回的承诺收集到一个数组中,然后使用Promise.when()(Promise.all() 的同义词)等待这些承诺的履行

    为了更清楚,排除“需要保存”的逻辑,所以这个云功能只能处理数据库......

    Parse.Cloud.define("reset", function(request, response) {
        var Query = new Parse.Query("price");
        Query.equalTo('isActive', true);
        Query.find({useMasterKey:true}).then((results) => {
            console.log("Found " + results.length + " price rows");
            // assuming ES6 or something like underscore
            let pricesToSave = results.filter(price => priceNeedsSave(price));
    
            // here's the important part, collect the promise from each save
            // proceed only after the promises have completed
            let promises =  pricesToSave.map(price => price.save(null, {useMasterKey:true}));
            return Parse.Promise.when(promises).then(() => pricesToSave.length);
        }).then(count => {
            response.success("Updated " + count +" price rows");
        }).catch(error => {
            response.error("Failed to fetch from price" + error );
        });
    }
    

    为了完整起见,下面是分解出的需求保存逻辑。 (OP应该检查一下,我只是复制了循环体)......

    function priceNeedsSave(price) {
        var isSaveNeeded = false;
        var currentDate = moment()
    
        var valid_till_date = price.get('valid_till_date');
        if (valid_till_date == null) {
            // if user had not selected valid_till_date then set to expire after system max no of days
            var updatedAt = price.get('updatedAt');
            if (currentDate.diff(updatedAt,'days') > 10) {
              console.log("Permanent change row to be set inactive. Updated at - " + currentDate.diff(updatedAt)+ updatedAt)
                price.set('isActive',false)
                isSaveNeeded = true
            }
        } else if (currentDate.diff(valid_till_date) > 0) {
            // check whether valid_till_date has passed
            console.log("Found row with elapsed valid date "  + price.id)
            price.set("isActive",false)
            isSaveNeeded = true
        }
        return isSaveNeeded;
    }
    

    【讨论】:

    • 我怀疑异步但不知道如何处理 javascript 代码。我必须说这个“承诺”概念比想象的要花更多的时间来掌握!!将尝试您的代码但有一个问题 - “results.filter(price =>”一次传递一个 Parse 对象以运行是否正确?如果是这样,那么不需要 for 循环对吗?
    • @ashishn,还请注意 Parse.Object 实现了dirty(),因此另一种方法是仅更改该函数中的价格对象并在 price.dirty() 上进行过滤。
    • 这里有一些关于 Promise 的提示。虽然 Parse 有它自己的 Parse.Promise 类,但它们是“骨干”样式,并且与其他骨干样式的 Promise 兼容,靠近每个带有服务器调用的 API 都会使用。当您使用.then().always() 等添加回调时,其结果将沿承诺链传递。如果它已经包含在一个 Promise 中,它将酌情调用下一个成功或错误处理程序。如果不是,它会自动包装在一个已解决的承诺中。如果没有返回,一旦到达块的末尾,一个空的已解决承诺
    • 被返回,即使有异步代码仍在运行但确实有返回值。确保如果在另一个内部调用异步方法,则使用 return 语句等待并返回嵌套 promise 的结果。此外,如果您的承诺失败,并且您的 .then()s 只有成功处理程序,则错误将一直沿链传递到下一个错误处理程序。另请注意,一旦错误处理程序以相同的方式工作 - 它将返回其值并传递它。如果你不返回一个值,它会返回一个空的已解决承诺!这让我很难受。
    • 要小心后一个问题,因为它可能会导致意外行为,您认为您正在捕获错误但函数返回成功,或者因为链的成功处理程序中的下一个链接预期值而崩溃没有通过,因为它从错误处理程序中获得了空的已解决承诺。确保你适当地“打破”你的链,或者更好的是,在你的外链上只有一个错误处理程序,所以任何失败的承诺总是会一直传递下去。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-02
    • 1970-01-01
    • 2013-11-10
    • 1970-01-01
    • 2017-07-30
    • 1970-01-01
    • 2015-08-02
    相关资源
    最近更新 更多