jQuery - 回调无法正常工作

时间:2017-04-06 14:15:42

标签: jquery ajax callback underscore.js

我从api调用返回了以下json。我想检查是否为某些产品记录了特定类型的事件,如果它返回了正确的消息并退出单击处理程序,则继续。我有一个名为hasEvent的函数来执行此检查。但是当我从someOtherFunction调用此函数时,即使检查为真,也不会返回任何消息?

{
  "item": {
    "Event": [
       {
         "EventType": {
             "Description": "New order"
          },
         "EventSubType": {
             "Description": "Awaiting payment"
          }
      },
      {
         "EventType": {
             "Description": "New order"
          },
          "EventSubType": {
             "Description": "Dispatched"
          }
      }
    ],
    "Errors": {
       "Result": 0,
       "Message": ""
    },
    "RecordCount": 2
  }
}


var getEvents = function (callback) {

    var orderId = $("#Id").val();

    $.getJSON('api/events?id=' + orderId)
         .done(function (data) {
               callback(data);
         }).fail(function (jqXHR, textStatus, err) {
             return;
        });

}


var hasEvent = function (productType, callback) {

    var msg;

    getEvents(function (data) {

       _.find(data.item.Event, function (event) {

           if (event.EventType.Description == 'New order' && 
               event.EventSubType.Description == 'Dispatched' && 
               productType = 'xyz') {

               msg = 'Some message';
               return true;
           }

           if (event.EventType.Description == 'New order' && 
               event.EventSubType.Description == 'Awaiting payment' && 
               productType = 'xyz') {

               msg = 'A different message';
               return true;
           }

           // Check for Some more conditions and return appropriate message

           return false;
      });

      if (msg)
         callback(msg);

   });


}


var someOtherFunction = function () {

    $('.myselector').click(function (e) {

        var productType = $(this).attr("data-product-type");

        hasEvent(productType, function(msg) {
            alert(msg);
            // exit click event handler
            return;
        });

        // otherwise do some other stuff

        return false;
    }
}

上述代码有什么问题?

*更新*

我已根据Griffins解决方案通过向hasEvent函数添加回调来更新代码,但现在如果显示警报,如何退出以下点击处理程序。以下只是继续执行,直到click处理程序中的所有操作都完成,这不是我想要的 - 如果有事件和警报显示,我想退出处理程序:

$('.myselector').click(function (e) {

    var productType = $(this).attr("data-product-type");

    hasEvent(productType, function(eventMsg) {
        alert(msg);
        // exit click event handler
        return;
    });

    // Do some other stuff only if no events

    return false;
}

1 个答案:

答案 0 :(得分:0)

代码中的问题是$.getJSON是异步的,这意味着当您执行它时,它会启动一个在下一行代码运行之前无法完成的操作。完成后,您传递给.done的回调将会执行,但在此期间,您的大多数其他代码都已经运行。这意味着当您致电hasEvents时,您正在初始化msgundefined,然后通过getEvents将在您的ajax呼叫返回时调用的回调。但是,由于该回调不会立即执行,hasEvents会继续并返回msg,这仍然等于undefined,这是Javascript中的虚假值。这意味着即使您的ajax调用返回并执行回调,hasEvent(productType)已经评估为false。

一种可能的解决方案是给hasEvent提供第二个参数,这是一个回调。然后在_.find中,您可以使用消息执行该回调而不是返回它,如下所示:

var getEvents = function (callback) {

  var orderId = $("#Id").val();

  $.getJSON('api/events?id=' + orderId)
    .done(function (data) {
      callback(data);
    }).fail(function (jqXHR, textStatus, err) {
      return;
    });

}


var hasEvent = function (productType, callback) {

  var msg = null;

  getEvents(function (data) {

    _.find(data.item.Event, function (event) {

      if (event.EventType.Description == 'New order' && 
        event.EventSubType.Description == 'Dispatched' && 
        productType = 'xyz') {

        msg = 'Some message';
        return true;
      }

      if (event.EventType.Description == 'New order' && 
        event.EventSubType.Description == 'Awaiting payment' && 
        productType = 'xyz') {

        msg = 'A different message';
        return true;
      }

      // Check for Some more conditions and return appropriate message

      return false;
    });

    callback(msg);


  });


}

var someOtherFunction = function () {

  $('.myselector').click(function (e) {

    var productType = $(this).attr("data-product-type");
    hasEvent(productType, function(eventMsg) {
      if (eventMsg) {
        console.log(eventMsg);
        alert(eventMsg);
      } else {
        console.log('there was no event!')
      }
    })
  }
}

或者,异步jquery函数返回promises,所以你可以这样做:

var getEvents = function (callback) {
  var orderId = $("#Id").val();
  return $.getJSON('api/events?id=' + orderId);
}


var hasEvent = function (productType) {
  return getEvents()
    .then(function (data) {

      var foundEvent = _.find(data.item.Event, function (event) {

        if (event.EventType.Description == 'New order' && 
           event.EventSubType.Description == 'Dispatched' && 
           productType = 'xyz') {
        }

        // Check for Some more conditions and return appropriate message

        return false; // if you don't return, it's undefined, which is a falsy value and has the same effect as returning false in _.find
      });

      return 'some message';

    });

}


var someOtherFunction = function () {

  $('.myselector').click(function (e) {

    var productType = $(this).attr("data-product-type");
    hasEvent(productType)
      .then(function(eventMsg) {
        console.log(eventMsg);
        alert(eventMsg);
      });
  }
}