синхронный вызов ajax - показать div перед вызовом - PullRequest
0 голосов
/ 19 марта 2019

Мне нужно, чтобы div, который покрывал весь мой экран, отображался до вызова sync ajax.

Но, похоже, что абсолютно ничего, что я пытаюсь сделать, приводит к изменению DOM, чтобы показать этот div передAjax Call.Экран «зависает», и div отображается только после выполнения вызова ajax.

Я уже пробовал «тысячи» подходов, но, похоже, ничто не может запустить ajax только после изменения DOM (показываетdiv).

HTML

[...]
<body>
    <div id="loadingDiv" style="display: none; width: 100%; height: 100%; background-color: #004000; position: absolute; z-index:10000;"></div>
[...]

javascript

[...]
$("#loadingDiv").css("display", "block");
var ajaxOp;
$.ajax({
    type: someType,
    url: someUrl,
    data: someData,
    dataType: someDataType,
    async: false,
    success: function (someArg) {
        ajaxOp = someArg;
    },
    error: function (someArg0, someArg1, someArg2) {
        // do something
    }
});
return ajaxOp;
[...]

ПРИМЕЧАНИЕ I: Я использую JQuery.
ПРИМЕЧАНИЕ II: «ajaxOp» не может быть «неопределенным».


ОБНОВЛЕНИЕ: В надежде, что это поможет пониманию и по просьбе @Felipe Dutra FerreiraЯ поместил еще несколько объяснений по поводу проблемы в обновлении ниже ...

РЕАЛЬНЫЙ СЛУЧАЙ: У меня есть приложение с несколькими устаревшими кодами, которые используют libray js с функцией, которая, в свою очередь, делает вызовы ajax (давайте назовем это "определенной функцией").Мы пытаемся обновить это приложение, чтобы оно отображало «экран загрузки» во время вызовов ajax (а не просто «блокировало» интерфейс во время этих вызовов).Таким образом, самый простой способ справиться с этой проблемой - это отобразить «экран загрузки» сразу после вызовов «определенной функции» и до того, как он выполнит вызовы ajax.Также обратите внимание, что «определенные функции» возвращают выходные данные вызова ajax, и эти выходные данные будут «неопределенными», если этот вызов не выполняется синхронно, то есть код может продолжиться только после того, как этот вызов ajax будет иметь выходные данные.

Ответы [ 2 ]

2 голосов
/ 19 марта 2019

Я написал для вас следующее.

ПОЖАЛУЙСТА, СМОТРИТЕ НА СЛЕДУЮЩИЙ ПРИМЕР В МОЕМ ГИТУБЕ


MyGithubLink


поскольку у меня есть полностью рабочий пример, который я старался изо всех сил помочь вам. здесь вы увидите использование Jquery CallBack Methods и структуру обещаний, с которыми, по-видимому, у вас возникают проблемы. пожалуйста, прокомментируйте меня, сообщив мне, если это окончательное решение, поскольку я полон решимости помочь вам.

Нажмите на JSBin, чтобы увидеть мой образец => https://jsbin.com/xeloful/edit?html,output

<body onload="myFunction()" style="margin:0;"></body>

это то, на что я хочу обратить ваше внимание ... пожалуйста, обратитесь, если вам все еще нужна помощь ... или если это не помогло ...

Или вы можете запустить фрагмент здесь, в StackOverflow. Ниже я использую $(myFunction) вместо onload="myFunction()", что более привычно для пользователей jQuery. Нажмите «Запустить фрагмент» ниже, чтобы увидеть результаты.

function showPage() {
    document.getElementById("loader").style.display = "none";
    document.getElementById("myDiv").style.display = "block";
};

function myFunction() {
    //Showing a Div prior to call as promised...
    $("#redSquare").fadeIn(3000).fadeOut(3000, function () {

        //Making the following API Call that will receive a random email from a random user...
        $.ajax({
            url: 'https://randomuser.me/api/',
            dataType: 'json',
            success: showPage
        }).done(function (res, req) {
            //Spitting out information about the HTTP call made...
            console.log(res);
            console.log(req);
            //Storing the email in the following variable...
            var RandomEmail = res.results[0].email;
            //Displaying the email in the console...
            console.log(RandomEmail);
            //Injecting the following email to the DOM
            document.getElementById("randomEmail").innerHTML = RandomEmail;
        });
    });
}

//When the body loads, render this function as seen in the body HTML tag with the onload... This is the jQuery way to do it...
$(myFunction);
#redSquare {
    display: none;
    width: 100vw;
    height: 100vh;
    background-color: crimson;
}

/* Center the loader */
#loader {
    position: absolute;
    left: 50%;
    top: 50%;
    z-index: 1;
    width: 150px;
    height: 150px;
    margin: -75px 0 0 -75px;
    border: 16px solid #f3f3f3;
    border-radius: 50%;
    border-top: 16px solid #3498db;
    width: 120px;
    height: 120px;
    -webkit-animation: spin 2s linear infinite;
    animation: spin 2s linear infinite;
}


@-webkit-keyframes spin {
    0% {
        -webkit-transform: rotate(0deg);
    }

    100% {
        -webkit-transform: rotate(360deg);
    }
}

@keyframes spin {
    0% {
        transform: rotate(0deg);
    }

    100% {
        transform: rotate(360deg);
    }
}

/* Add animation to "page content" */
.animate-bottom {
    position: relative;
    -webkit-animation-name: animatebottom;
    -webkit-animation-duration: 1s;
    animation-name: animatebottom;
    animation-duration: 1s
}

@-webkit-keyframes animatebottom {
    from {
        bottom: -100px;
        opacity: 0
    }

    to {
        bottom: 0px;
        opacity: 1
    }
}

@keyframes animatebottom {
    from {
        bottom: -100px;
        opacity: 0
    }

    to {
        bottom: 0;
        opacity: 1
    }
}

#myDiv {
    display: none;
    text-align: center;
}

#randomEmail {
    color: white;
    background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="redSquare">
    <!--Making this Appear for 3 Seconds prior to Ajax...-->
</div>

<div id="loader"></div>

<div style="display:none;" id="myDiv" class="animate-bottom">
    <h2>Tada!</h2>
    <p>Some text in my newly loaded page..</p>
    <h1>
        RandomEmail: <span id="randomEmail"></span>
    </h1>
</div>
0 голосов
/ 20 марта 2019

A Обходной путь - использовать приведенную ниже функцию, которая позволяет отображать «экран загрузки» в системе при выполнении синхронных вызовов («ajax»). Его можно легко адаптировать для использования с устаревшими кодами.

Поймите, что «ajax» блокирует модификацию «DOM», хотя ЭТО ВЫПОЛНЕНО ДО ЭТОГО ВЫЗОВА. Этот подход будет работать ТОЛЬКО, если он используется в ПЕРВЫЙ ВРЕМЯ процесса, который раньше включал некоторый синхронизирующий вызов ajax. По сути, он создает временное окно (50 мс) для обновления DOM перед выполнением желаемой функции / метода ("appFunc"). Использование этой функции имеет смысл только в ситуациях, которые требуют использования вывода вызова sync ajax сразу после его выполнения.

ПРИМЕР ИСПОЛЬЗОВАНИЯ: <button type="button" onclick="opSyncLoading(login, [this.form])">

  • В этом примере мы используем «возможность» действия пользователя, чтобы создать временное окно для потока и отобразить «экран загрузки». Обратите внимание, что функция «login» не возвращает никакого типа вывода. Обратите внимание, что все, что происходит после функции «login», будет выполняться «SYNC».
  • Это ограничение связано с тем, что в JS / DOM есть только один «поток» для обработки всего, то есть, например, нет способа ждать с помощью «сна», поскольку не существует никакого типа эффективного параллелизма. , Одним из решений может быть использование «веб-работника», но это выходит за рамки поставленного вопроса.
  • НЕОБХОДИМО избегать использования синхронных вызовов "ajax", поскольку, поскольку оно вызывает побочные эффекты в работе JS и HTML, помимо того, что оно считается плохой практикой. Его использование должно быть ограничено устаревшими кодами или ситуациями, когда это строго необходимо.

СОВЕТ: Обратите внимание, что если на «экране загрузки» есть анимированный gif-файл, он будет «заблокирован» до завершения вызова «ajax», однако в некоторых современных браузерах эта проблема не возникает. , В крайнем случае есть вероятность, что изображение останется «анимированным», если оно загружено в iframe (https://stackoverflow.com/a/16704839/3223785).

function opSyncLoading(appFunc, appFuncArgs) {
    if (typeof appFuncArgs === "undefined" || appFuncArgs === "") {
        appFuncArgs = [];
    }
    $("#loadingDiv").fadeIn(500, setTimeout(function () {

        // NOTE: Passing unknown arguments in quantity and nature to a callback function. By Questor
        // [Ref.: https://stackoverflow.com/a/49680525/3223785 ]
        appFunc.apply(this, appFuncArgs);

    }, 50));
}

Спасибо! = D

...