Passing an async function to settings.ajax causes error when reload is called

Passing an async function to settings.ajax causes error when reload is called

ChrisHSandNChrisHSandN Posts: 4Questions: 2Answers: 0

Passing an async function to settings.ajax causes an "xhr.abort is not a function" error when reload is called:

Testcase:
http://live.datatables.net/kevuqoro/1/edit?html,js,console,output

Code

  var tableAsync = $('#async').DataTable({
    ajax: async (dtAjaxData, callback) => {
      callback({
        draw: dtAjaxData.draw,
        recordsTotal: 0,
        recordsFiltered: 0,
        data: [],
      });
    },
  });

  tableAsync.ajax.reload();

Error

jquery.dataTables.js:7582 Uncaught TypeError: xhr.abort is not a function
    at __reload (VM48 jquery.dataTables.js:7582)
    at _Api.<anonymous> (VM48 jquery.dataTables.js:7644)
    at _Api.iterator (VM48 jquery.dataTables.js:7029)
    at _Api.<anonymous> (VM48 jquery.dataTables.js:7643)
    at Object.reload (VM48 jquery.dataTables.js:7196)
    at HTMLDocument.<anonymous> (<anonymous>:26:19)
    at j (VM47 jquery-1.11.3.min.js:2)
    at Object.fireWith [as resolveWith] (VM47 jquery-1.11.3.min.js:2)
    at Function.ready (VM47 jquery-1.11.3.min.js:2)
    at HTMLDocument.J (VM47 jquery-1.11.3.min.js:2)

Answers

  • allanallan Posts: 63,208Questions: 1Answers: 10,415 Site admin

    Passing an async function to settings.ajax causes an "xhr.abort is not a function" error when reload is called:

    Yes this is expected. DataTables' Ajax handling does not currently support Promises - nor does the documentation say that it does. If you found something that says it does, could you give me a link to it so I can correct it please.

    ajax: async (dtAjaxData, callback) => {

    You are using the callback to do the complete - so I don't understand why it would need to be an async function?

    Allan

  • ChrisHSandNChrisHSandN Posts: 4Questions: 2Answers: 0

    Yes this is expected. DataTables' Ajax handling does not currently support Promises

    I think I have a better understanding now. It seems the bug is triggered by any truthy return statement from within an ajax callback function.

    The async was a bit of a red herring, it just happens that async functions always return (with a Promise) which counts as 'truthy;.

    var tableAsync = $('#async').DataTable({
      ajax: (dtAjaxData, callback) => {
        callback({
          draw: dtAjaxData.draw,
          recordsTotal: 0,
          recordsFiltered: 0,
          data: [],
        });
    
        return true;
      },
    });
     
    tableAsync.ajax.reload();
    

    I would expect DataTables to call the provided ajax callback function, ignore any return value, and rely on the callback to trigger the logic?

    The documentation doesn't mention anything about return values when using a function https://datatables.net/reference/option/ajax#function.

    You are using the callback to do the complete - so I don't understand why it would need to be an async function?

    The real code was much more complex than this example and relied on asynchronous calls to be run to produce the result before the callback could be called.

  • allanallan Posts: 63,208Questions: 1Answers: 10,415 Site admin

    I would expect DataTables to call the provided ajax callback function, ignore any return value, and rely on the callback to trigger the logic?

    Ah - you can't return any value. Internally DataTables returns the jQuery XHR object so it can store and reference it, and that is exposed via the API as well. If you remove your return true' it will work fine - otherwise DataTables assumes that the return is an XHR object.

    Is it possible to not return anything from your function (or return undefined)?

    Allan

  • ChrisHSandNChrisHSandN Posts: 4Questions: 2Answers: 0

    Is it possible to not return anything from your function (or return undefined)?

    The return true was simply a demonstration of the behaviour which was the cause of the original issue, it goes back to the point that:

    ajax: async () => {
        // do stuff...
    };
    

    Effectively behaves like:

    ajax: () => {
        // do stuff...
        return new Promise();
    };
    

    Which then hits the "DataTables assumes that the return is an XHR object"...

    You can workaround it using a self invoking function so nothing is returned (but this feels like a hack):

    ajax: () => {
        (async () => {
            // do stuff...
        }());
    };
    

    It seems that DataTables is being naive to assume any truthy return value from that callback function means it is a jQuery XHR object. Can it not be typeof/instanceof etc. checked?

    p.s. thanks for all your replies :) I don't mean to keep going on about this, I just have a feeling async functions are only going to increase in use and I won't be the last to hit this (fairly hard to debug) issue.

  • allanallan Posts: 63,208Questions: 1Answers: 10,415 Site admin

    It seems that DataTables is being naive to assume any truthy return value from that callback function means it is a jQuery XHR object. Can it not be typeof/instanceof etc. checked?

    Yes. It is / was naive - it was an assumption I made (many) years ago that an XHR return would be all that was of interest from that function. The web has moved on since then and we really do need to support Promises for that sort of thing. It is on the roadmap!

    Until then, the other option would be to use:

    ajax: (dtAjaxData, callback) => {
      new Promise((resolve, reject) => {
        // ... do stuff
        callback( ... );
        resolve();
      });
    };
    

    A Promise (and thus an Async function) which resolves to the data, rather than needing to use callback(...) would be better.

    Allan

This discussion has been closed.