需要帮助在JSON / AJAX帖子上实现Deferred

时间:2013-10-31 16:33:49

标签: jquery ajax json jquery-deferred

我正在编写一个测验,通过异步AJAX / JSON帖子向数据库发送答案。数据库返回一个指示器来判断答案是否正确。

一位同事建议使用$ .Deferred,因为没有办法告诉数据库调用返回可能需要多长时间。我一直无法找到一个用AJAX帖子做这个的明显例子。我认为其中一位StackOverflow专家可以为此提供指导。

此代码位于调用函数中,当单击“提交答案”按钮时,该函数将被执行。

     var answerResult = recordAnswer(answer);
     if (answerResult.IsAnswerCorrect) {
        // Show student if her quiz answer was correct.
     }

这是recordAnswer功能。这需要在对象中返回几个值(IsAnswerCorrect和IsQuizCompleted)。我的表单成功进行了AJAX调用,值被返回到'结果'。但有时返回的'answerResult'值在上面的调用代码中以'undefined'形式返回,因此会中断。我认为将此更改为延期通话将避免此问题。

  var recordAnswer = function (answer) {

  var quizSessionQuestionId = $('#hidden_quizSessionQuestionId').val();
  var numberOfHintsUsed = 0;

  var answerResult;

  $.ajax({
     url: QuizConfig.RecordAnswerDataAction, // Tied to RecordAnswer in BaseQuizController.
     type: 'POST',
     async: false,
     dataType: 'json',
     data: {
        "quizSessionQuestionId": quizSessionQuestionId,
        "value": answer,
        "numberOfHintsUsed": numberOfHintsUsed,
        "markCompleteIfWrong": false
     },
     success: function (result) {
        answerResult = result;
     },
     error: function (request, errorm) {
        jAlert("Unable to record answer.", "An error occurred while saving this answer.");
        return;
     }
  });

  return answerResult;
};

在研究这个时,我发现以下教程指出我在上面应用的模式(分配answerResult =结果)是“小心破坏代码”,因为“A代表异步”。 :) http://jqfundamentals.com/chapter/ajax-deferreds

无论如何,请告诉我如何调整上面的代码以使用延迟的方法,而不是我到目前为止已经破碎的方法。谢谢你的帮助。

3 个答案:

答案 0 :(得分:1)

$.Deferred()对象最好被认为是承诺的经纪人。使用promises进行异步编程的一种常见模式是使用返回promises而不是value的函数。例如,您可以重写您发布的代码,如下所示:

var recordAnswer = function (answer) {
    ...
    var answerResult = $.Deferred();

    $.ajax({
        ...
        success: function (result) {
            answerResult.resolve(result);
        },
        error: function (request, errorm) {
            jAlert("Unable to record answer.", "An error occurred while saving this answer.");
            answerResult.reject();
        }
    });

    return answerResult.promise();
};

使用recordAnswer的代码可以听取解决的承诺,而不是试图立即使用返回的值:

var fetchingAnswer = recordAnswer(answer);

fetchingAnswer.then(function(result) {
    // do stuff with the result
}

deferred.then()将在拒绝或解决后执行,因此您可能希望使用deferred.done()(对于已解决的承诺)和deferred.fail()(对于被拒绝的承诺)。< / p>

==========================================

以下是基于@giaour建议的完整实施,对于任何感兴趣的人。感谢。

单击提交按钮时会调用此方法。

     var fetchAnswer = recordAnswer(answer);
     fetchAnswer.then(function (result) {
        // Do something
        recalculateProgress(result.IsComplete, result.IsAnswerCorrect);
     });

这使用延迟的AJAX帖子。

var recordAnswer = function (answer) {

  var quizSessionQuestionId = $('#hidden_quizSessionQuestionId').val();
  var numberOfHintsUsed = 0;

  var promiseBroker = $.Deferred();
  $.ajax({
     url: QuizConfig.RecordAnswerDataAction,
     type: 'POST',
     async: false,
     dataType: 'json',
     data: {
        "quizSessionQuestionId": quizSessionQuestionId,
        "value": answer,
        "numberOfHintsUsed": numberOfHintsUsed,
        "markCompleteIfWrong": false
     },
     success: function (result) {
        promiseBroker.resolve(result);
     },
     error: function (request, errorm) {
        jAlert("Unable to record answer.", "An error occurred while saving this answer.");
        promiseBroker.reject();
        return;
     }
  });

  return promiseBroker.promise();
};

感谢大家的帮助。

答案 1 :(得分:0)

异步代码应该是这样的,使用回调函数

 var answerResult = recordAnswer(answer, function(answerResult){
     if (answerResult.IsAnswerCorrect) {
        // Show student if her quiz answer was correct.
     }
 );

 var recordAnswer = function (answer , cb) {
  $.ajax({
    .......
     success: function (result) {
        cb(result);
     },
    .......

答案 2 :(得分:0)

主要的问题是,这样你就不能确保return answerResult;将在成功函数后执行,尽管你将async设置为false。

所以,我认为更好的方法是在成功触发并执行必须执行的操作时触发的回调函数。您可以将调用对象传递给recordAnswer函数,并在回调函数上使用它。