3

我正在编写一个测验,通过异步 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”值在上面的调用代码中返回为“未定义”,因此会中断。我相信将其更改为延迟调用将避免该问题。

  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 = 结果)是“CAUTION BROKEN CODE”,因为“A 代表异步”。:) http://jqfundamentals.com/chapter/ajax-deferreds

无论如何,请告诉我如何调整上面的代码以使用延迟方法,而不是我迄今为止所采用的破碎方法。谢谢你的帮助。

4

3 回答 3

2

最好将$.Deferred()对象视为 promise 的代理。使用 Promise 进行异步编程的一种常见模式是使用返回 Promise 而不是返回值的函数。例如,您可能会重写您发布的代码,如下所示:

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可以监听 promise 以解决问题,而不是尝试立即使用返回的值:

var fetchingAnswer = recordAnswer(answer);

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

deferred.then()将在拒绝或解决后执行,因此您可能希望使用deferred.done()(for a resolved promise) 和deferred.fail()(for a denied promise) 来代替。

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

以下是我根据@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();
};

谢谢大家的帮助。

于 2013-10-31T16:59:51.677 回答
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);
     },
    .......
于 2013-10-31T16:38:55.430 回答
0

return answerResult;主要问题是,尽管您将 async 设置为 false,但您无法保证将在成功后执行功能。

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

于 2013-10-31T16:46:01.610 回答