同步ajax调用-调用前显示div

时间:2019-03-19 02:59:49

标签: javascript jquery ajax synchronous

在进行同步Ajax调用之前,我需要制作一个覆盖整个屏幕的div。

但是似乎绝对没有我尝试做的事情导致DOM被修改以在ajax调用之前显示此div。屏幕将“冻结”,并且只有在执行了ajax调用之后才显示div。

我已经尝试了成千上万种方法,但是似乎只有在DOM修改后(显示div),才能使ajax运行。

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;
[...]

注意我::我正在使用JQuery。
注意II:不能将“ ajaxOp”定义为“ undefined”。


更新:希望对理解有所帮助,并应@Felipe Dutra Ferreira的要求,在下面的更新中针对该问题进行了更多解释...

真实案例:我有一个带有多个旧代码的应用程序,这些旧代码消耗了libray js,而该函数又进行了ajax调用(我们称之为“ certainfunction”)。我们正在尝试更新此应用程序,以使其在ajax调用期间显示“加载屏幕”(而不仅仅是在这些调用期间“锁定” UI)。因此,处理此问题的最简单方法是在对“ certainfunction”的调用之后以及在运行ajax调用之前显示“加载屏幕”。还要注意,“ certainfunction”返回ajax调用的输出,并且一旦不同步执行此调用,该输出将是“ undefined”,也就是说,只有在此ajax调用具有输出之后,代码才能继续。

2 个答案:

答案 0 :(得分:2)

我为您写了以下内容。

请查看我的GITHUB中的以下示例


  

MyGithubLink


因为我有一个完整的示例,我已尽力为您提供帮助。 在这里,您将看到Jquery CallBack Methods和Promise框架的使用,这似乎是您遇到的问题。请回覆我,让我知道这是否是最终解决方案,因为我决心为您提供帮助。

单击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>

答案 1 :(得分:0)

一种解决方法是使用下面的功能,当我们进行同步呼叫(“ ajax”)时,该功能允许在系统上显示“正在加载屏幕”。可以很容易地将其修改为与旧版代码一起使用。

认识到即使在此调用之前执行了“ ajax”也会阻止对“ DOM”的修改。如果此方法仅在之前涉及某个同步ajax调用的进程的第一时间使用,则该方法才有效。基本上,它会在执行所需功能/方法(“ appFunc”)之前创建一个时间窗口(50毫秒)以更新DOM。仅在需要在执行同步ajax调用后立即使用输出的情况下,才可以使用此功能。

使用示例:<button type="button" onclick="opSyncLoading(login, [this.form])">

  • 在此示例中,我们利用用户操作的“最终性”来创建线程的时间窗口并显示“加载屏幕”。请注意,“登录”功能不会返回任何类型的输出。请注意,“登录”功能之后发生的所有事情都将以“同步”方式完成。
  • 此限制是由于以下事实: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