JSFiddle - React, Tailwind, and code Playground

JavaScript

function doAjax(ajaxArgs, attempt) {
    var wrappedDfd = $.Deferred();

    (function nestedCall() {
        $.ajax(ajaxArgs).then(wrappedDfd.resolve, function() {
            attempt--;
            if (attempt > 0) {
                nestedCall();
            } else {
                wrappedDfd.reject();
            }
        });
    })();
    
    return wrappedDfd.promise();
};

function doAjax2(callFactory, attempt) {
    var wrappedDfd = $.Deferred();

    (function nestedCall() {
        callFactory().then(wrappedDfd.resolve, function() {
            attempt--;
            if (attempt > 0) {
                nestedCall();
            } else {
                wrappedDfd.reject();
            }
        });
    })();
    
    return wrappedDfd.promise();
};

var createCallFactory = function(fail, maxRetry) {
    return function() {
        console.log('call factory maxRetry = ' + maxRetry);
        return --maxRetry > 0 ? $.Deferred().reject().promise() : $.Deferred()[fail ? "reject" : "resolve"]().promise();
    };
};

console.clear();
doAjax2(createCallFactory(false, 3), 3).then(function() { console.log('CALL OK'); }, function() { console.log('CALL KO'); });