需要帮助在JSON/AJAX post上实现延迟。

时间:2022-05-13 06:45:25

I'm writing a quiz that sends an answer to the database via an asynchronous AJAX/JSON post. The database returns an indicator to tell if the answer was correct.

我正在写一个测试,通过异步AJAX/JSON post向数据库发送一个答案。数据库返回一个指示符,以判断答案是否正确。

A colleague recommended using $.Deferred, since there is no way of telling how long it may take for the database call to return. I've been unable to find a clear example of doing this with an AJAX post. And I figured one of the * experts could provide guidance on this.

一位同事建议使用美元。延迟,因为无法知道数据库调用需要多长时间返回。我一直找不到一个用AJAX贴子做这件事的明确例子。我想*的一个专家可以提供指导。

This code is in the calling function which gets executed when a "Submit Answer" button is clicked.

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

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

Here is the recordAnswer function. This needs to return a couple of values in an object (IsAnswerCorrect and IsQuizCompleted). My form is successfully making the AJAX call, and values are being returned to the 'result'. But sometimes the 'answerResult' value that gets returned comes back as 'undefined' in the calling code above, and consequently breaks. I believe changing this to a deferred call will avoid that problem.

这是记录回答函数。这需要返回对象中的几个值(IsAnswerCorrect和IsQuizCompleted)。我的表单正在成功地进行AJAX调用,并将值返回到“result”。但是,有时返回的“应答结果”值在上面的调用代码中返回“未定义”,因此会中断。我相信把这个改成延期通话可以避免这个问题。

  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;
};

While researching this, I found the following tutorial which indicates the pattern that I applied above (of assigning answerResult = result) is "CAUTION BROKEN CODE" because "A is for Asynchronous." :) http://jqfundamentals.com/chapter/ajax-deferreds

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

At any rate, please show me how to adjust the code above to use a deferred methodology, rather than the broken approach that I have so far. Thanks for your help.

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

3 个解决方案

#1


1  

A $.Deferred() object is best thought of as a broker for promises. A common pattern for asynchronous programming with promises is to use functions that return promises rather than values. You might, for example, rewrite the code you posted as follows:

$. deferred()对象被认为是承诺的代理。带有承诺的异步编程的常见模式是使用返回承诺而不是值的函数。例如,您可以重写如下所示的代码:

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();
};

The code using recordAnswer can then listen to the promise for resolution rather than trying to immediate use the returned value:

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

var fetchingAnswer = recordAnswer(answer);

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

deferred.then() will execute after either a rejection or a resolution, so you might want to use deferred.done() (for a resolved promise) and deferred.fail() (for a rejected promise) instead.

then()将在拒绝或决议之后执行,因此您可能需要使用deferred.done()(用于已解决的承诺)和deferred.fail()(用于被拒绝的承诺)。

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

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

Below is my full implementation based on the recommendations of @giaour, for anyone who is interested. Thanks.

以下是我根据@giaour的建议为任何感兴趣的人提供的完整实现。谢谢。

This is called when the submit button is clicked.

当单击submit按钮时调用。

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

This uses deferred with the AJAX post.

这使用了AJAX post的deferred。

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();
};

Thanks for your help everyone.

谢谢大家的帮助。

#2


0  

Asynchronous code should be like this, using a callback func

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

 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);
     },
    .......

#3


0  

The main problem is that in this way you are going you can't assure that the return answerResult; will execute after success function, although you are setting async to false.

主要的问题是这样你就不能保证返回的结果;将在成功函数之后执行,尽管您将async设置为false。

So, I think a better approach would be a callback function that triggers when success triggers and do what it has to do. You can pass the calling object to the recordAnswer function and use it on nthe callback function.

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

#1


1  

A $.Deferred() object is best thought of as a broker for promises. A common pattern for asynchronous programming with promises is to use functions that return promises rather than values. You might, for example, rewrite the code you posted as follows:

$. deferred()对象被认为是承诺的代理。带有承诺的异步编程的常见模式是使用返回承诺而不是值的函数。例如,您可以重写如下所示的代码:

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();
};

The code using recordAnswer can then listen to the promise for resolution rather than trying to immediate use the returned value:

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

var fetchingAnswer = recordAnswer(answer);

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

deferred.then() will execute after either a rejection or a resolution, so you might want to use deferred.done() (for a resolved promise) and deferred.fail() (for a rejected promise) instead.

then()将在拒绝或决议之后执行,因此您可能需要使用deferred.done()(用于已解决的承诺)和deferred.fail()(用于被拒绝的承诺)。

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

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

Below is my full implementation based on the recommendations of @giaour, for anyone who is interested. Thanks.

以下是我根据@giaour的建议为任何感兴趣的人提供的完整实现。谢谢。

This is called when the submit button is clicked.

当单击submit按钮时调用。

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

This uses deferred with the AJAX post.

这使用了AJAX post的deferred。

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();
};

Thanks for your help everyone.

谢谢大家的帮助。

#2


0  

Asynchronous code should be like this, using a callback func

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

 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);
     },
    .......

#3


0  

The main problem is that in this way you are going you can't assure that the return answerResult; will execute after success function, although you are setting async to false.

主要的问题是这样你就不能保证返回的结果;将在成功函数之后执行,尽管您将async设置为false。

So, I think a better approach would be a callback function that triggers when success triggers and do what it has to do. You can pass the calling object to the recordAnswer function and use it on nthe callback function.

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