如何让 javascript 代码*按顺序*执行

发布于 2024-08-28 16:13:52 字数 597 浏览 12 评论 0原文

好吧,我明白 Javascript 不是 C# 或 PHP,但我不断地回到 Javascript 中的一个问题——不是 JS 本身,而是我对它的使用。

我有一个函数:

function updateStatuses(){

showLoader() //show the 'loader.gif' in the UI

updateStatus('cron1'); //performs an ajax request to get the status of something
updateStatus('cron2');
updateStatus('cron3');
updateStatus('cronEmail');
updateStatus('cronHourly');
updateStatus('cronDaily');

hideLoader(); //hide the 'loader.gif' in the UI

}

事情是,由于 Javascript 强烈希望在代码中向前跳转,加载器永远不会出现,因为“hideLoader”函数会直接运行。

我该如何解决这个问题?或者换句话说,如何让 JavaScript 函数按照我在页面上编写的顺序执行......

Okay, so I appreciate that Javascript is not C# or PHP, but I keep coming back to an issue in Javascript - not with JS itself but my use of it.

I have a function:

function updateStatuses(){

showLoader() //show the 'loader.gif' in the UI

updateStatus('cron1'); //performs an ajax request to get the status of something
updateStatus('cron2');
updateStatus('cron3');
updateStatus('cronEmail');
updateStatus('cronHourly');
updateStatus('cronDaily');

hideLoader(); //hide the 'loader.gif' in the UI

}

Thing is, owing to Javascript's burning desire to jump ahead in the code, the loader never appears because the 'hideLoader' function runs straight after.

How can I fix this? Or in other words, how can I make a javascript function execute in the order I write it on the page...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

逆蝶 2024-09-04 16:13:52

出现该问题的原因是 AJAX 本质上是异步的。这意味着 updateStatus() 调用确实按顺序执行,但立即返回,并且 JS 解释器在从 AJAX 请求检索任何数据之前到达 hideLoader()

您应该在 AJAX 调用完成的事件上执行 hideLoader()

The problem occurs because AJAX is in its nature asynchronus. This means that the updateStatus() calls are indeed executed in order but returns immediatly and the JS interpreter reaches hideLoader() before any data is retreived from the AJAX requests.

You should perform the hideLoader() on an event where the AJAX calls are finished.

坠似风落 2024-09-04 16:13:52

如果您正在进行 AJAX 编程,您需要将 JavaScript 视为基于事件的而不是过程性的。您必须等到第一个调用完成才能执行第二个调用。执行此操作的方法是将第二个调用绑定到第一个调用完成时触发的回调。如果不了解 AJAX 库的内部工作原理(希望您正在使用库),我无法告诉您如何执行此操作,但它可能看起来像这样:

showLoader();

  updateStatus('cron1', function() {
    updateStatus('cron2', function() {
      updateStatus('cron3', function() {
        updateStatus('cronEmail', function() {
          updateStatus('cronHourly', function() {
            updateStatus('cronDaily', funciton() { hideLoader(); })
          })
        })
      })
    })
  })
});

想法是,updateStatus 接受其普通参数,以及完成时要执行的回调函数。将运行 onComplete 的函数传递到提供此类挂钩的函数中是一种相当常见的模式。

更新

如果您使用 jQuery,您可以在此处阅读 $.ajax()http://api.jquery.com/jQuery.ajax/

您的代码可能如下所示:

function updateStatus(arg) {
  // processing

  $.ajax({
     data : /* something */,
     url  : /* something */
  });

  // processing
}

您可以修改函数以将回调作为第二个参数像这样的东西:

function updateStatus(arg, onComplete) {
  $.ajax({
    data : /* something */,
    url  : /* something */,
    complete : onComplete // called when AJAX transaction finishes
  });

}

You need to think of JavaScript as event based rather than procedural if you're doing AJAX programming. You have to wait until the first call completes before executing the second. The way to do that is to bind the second call to a callback that fires when the first is finished. Without knowing more about the inner workings of your AJAX library (hopefully you're using a library) I can't tell you how to do this, but it will probably look something like this:

showLoader();

  updateStatus('cron1', function() {
    updateStatus('cron2', function() {
      updateStatus('cron3', function() {
        updateStatus('cronEmail', function() {
          updateStatus('cronHourly', function() {
            updateStatus('cronDaily', funciton() { hideLoader(); })
          })
        })
      })
    })
  })
});

The idea is, updateStatus takes its normal argument, plus a callback function to execute when it's finished. It's a reasonably common pattern to pass a function to run onComplete into a function which provides such a hook.

Update

If you're using jQuery, you can read up on $.ajax() here: http://api.jquery.com/jQuery.ajax/

Your code probably looks something like this:

function updateStatus(arg) {
  // processing

  $.ajax({
     data : /* something */,
     url  : /* something */
  });

  // processing
}

You can modify your functions to take a callback as their second parameter with something like this:

function updateStatus(arg, onComplete) {
  $.ajax({
    data : /* something */,
    url  : /* something */,
    complete : onComplete // called when AJAX transaction finishes
  });

}

顾北清歌寒 2024-09-04 16:13:52

我认为您需要做的就是在代码中包含以下内容:

async: false,

因此您的 Ajax 调用将如下所示:

jQuery.ajax({
            type: "GET",
            url: "something.html for example",
            dataType: "html",
            async: false,
            context: document.body,
            success: function(response){

                //do stuff here

            },
            error: function() {
                alert("Sorry, The requested property could not be found.");
            }  
        });

显然,其中一些需要针对 XMLJSON 等进行更改,但是async: false, 是这里的要点,它告诉 JS 引擎等待,直到成功调用返回(或失败,具体取决于),然后继续。
请记住,这样做有一个缺点,那就是整个页面变得没有响应,直到 ajax 返回!通常在几毫秒内,这不是什么大问题,但可能需要更长的时间。

希望这是正确的答案并且对您有所帮助:)

I thinks all you need to do is have this in your code:

async: false,

So your Ajax call would look like this:

jQuery.ajax({
            type: "GET",
            url: "something.html for example",
            dataType: "html",
            async: false,
            context: document.body,
            success: function(response){

                //do stuff here

            },
            error: function() {
                alert("Sorry, The requested property could not be found.");
            }  
        });

Obviously some of this need to change for XML, JSON etc but the async: false, is the main point here which tell the JS engine to wait until the success call have returned (or failed depending) and then carry on.
Remember there is a downside to this, and thats that the entire page becomes unresponsive until the ajax returns!!! usually within milliseconds which is not a big deals but COULD take longer.

Hope this is the right answer and it helps you :)

皇甫轩 2024-09-04 16:13:52

我们的一个项目中有类似的东西,我们通过使用计数器解决了它。如果您增加每次调用 updateStatus 的计数器,并在 AJAX 请求的响应函数中减少它(取决于您使用的 AJAX JavaScript 库)。

一旦计数器达到零,所有 AJAX 请求都将完成您可以调用hideLoader()

这是一个示例:

var loadCounter = 0;

function updateStatuses(){
    updateStatus('cron1'); //performs an ajax request to get the status of something
    updateStatus('cron2');
    updateStatus('cron3');    
    updateStatus('cronEmail');
    updateStatus('cronHourly');
    updateStatus('cronDaily');
}

function updateStatus(what) {
    loadCounter++;

    //perform your AJAX call and set the response method to updateStatusCompleted()
}

function updateStatusCompleted() {
    loadCounter--;
    if (loadCounter <= 0)
        hideLoader(); //hide the 'loader.gif' in the UI
}

We have something similar in one of our projects, and we solved it by using a counter. If you increase the counter for each call to updateStatus and decrease it in the AJAX request's response function (depends on the AJAX JavaScript library you're using.)

Once the counter reaches zero, all AJAX requests are completed and you can call hideLoader().

Here's a sample:

var loadCounter = 0;

function updateStatuses(){
    updateStatus('cron1'); //performs an ajax request to get the status of something
    updateStatus('cron2');
    updateStatus('cron3');    
    updateStatus('cronEmail');
    updateStatus('cronHourly');
    updateStatus('cronDaily');
}

function updateStatus(what) {
    loadCounter++;

    //perform your AJAX call and set the response method to updateStatusCompleted()
}

function updateStatusCompleted() {
    loadCounter--;
    if (loadCounter <= 0)
        hideLoader(); //hide the 'loader.gif' in the UI
}
等你爱我 2024-09-04 16:13:52

这与代码的执行顺序无关。

加载程序图像从不显示的原因是,当您的函数运行时,UI 不会更新。如果您在 UI 中进行更改,则在您退出该功能并将控制权返回给浏览器之前,它们不会显示。

您可以在设置图像后使用超时,让浏览器有机会在开始其余代码之前更新 UI:

function updateStatuses(){

  showLoader() //show the 'loader.gif' in the UI

  // start a timeout that will start the rest of the code after the UI updates
  window.setTimeout(function(){
    updateStatus('cron1'); //performs an ajax request to get the status of something
    updateStatus('cron2');
    updateStatus('cron3');
    updateStatus('cronEmail');
    updateStatus('cronHourly');
    updateStatus('cronDaily');

    hideLoader(); //hide the 'loader.gif' in the UI
  },0);
}

还有另一个因素也可能使您的代码看起来执行无序。如果您的 AJAX 请求是异步的,该函数将不会等待响应。当浏览器收到响应时,处理响应的函数将运行。如果您想在收到响应后隐藏加载程序图像,则必须在最后一个响应处理程序函数运行时执行此操作。由于响应不必按照您发送请求的顺序到达,因此您需要计算最后一个响应到达时您需要知道的响应数量。

This has nothing to do with the execution order of the code.

The reason that the loader image never shows, is that the UI doesn't update while your function is running. If you do changes in the UI, they don't appear until you exit the function and return control to the browser.

You can use a timeout after setting the image, giving the browser a chance to update the UI before starting rest of the code:

function updateStatuses(){

  showLoader() //show the 'loader.gif' in the UI

  // start a timeout that will start the rest of the code after the UI updates
  window.setTimeout(function(){
    updateStatus('cron1'); //performs an ajax request to get the status of something
    updateStatus('cron2');
    updateStatus('cron3');
    updateStatus('cronEmail');
    updateStatus('cronHourly');
    updateStatus('cronDaily');

    hideLoader(); //hide the 'loader.gif' in the UI
  },0);
}

There is another factor that also can make your code appear to execute out of order. If your AJAX requests are asynchronous, the function won't wait for the responses. The function that takes care of the response will run when the browser receives the response. If you want to hide the loader image after the response has been received, you would have to do that when the last response handler function runs. As the responses doesn't have to arrive in the order that you sent the requests, you would need to count how many responses you got to know when the last one comes.

等风也等你 2024-09-04 16:13:52

正如其他人指出的那样,您不想进行同步操作。拥抱异步,这就是 AJAX 中的 A 所代表的意思。

我只想提一下关于同步与异步的一个很好的类比。您可以阅读 GWT 论坛上的整个帖子,我只是包括相关的类比。

想象一下,如果你愿意......

你坐在沙发上看
电视,并且知道你已经出局了
啤酒,你请你的配偶取悦
跑到酒类商店并
给你拿一些。一看到
你的配偶走出前门,
你从沙发上站起来并滚动
进入厨房并打开
冰箱。令你惊讶的是,没有
啤酒!

当然没有啤酒,你的
配偶仍在旅途中
酒类商店。你必须等到
[s]他在你期待之前就回来了
喝杯啤酒。

但是,你说你想要它同步?再想象一下...

...配偶走出门...现在,
你周围的整个世界都停止了,你
不要呼吸,回答
门,或者看完你的节目
当他跑过城镇去
去拿你的啤酒来。你只需坐下来
那里没有移动肌肉,并且
变成蓝色直到你输了
意识……醒来一些
无限期的时间之后被包围
急救人员和配偶说哦,嘿,我
喝了啤酒。

这正是当您坚持执行同步服务器调用时所发生的情况。

As others have pointed out, you don't want to do a synchronous operation. Embrace Async, that's what the A in AJAX stands for.

I would just like to mention an excellent analogy on sync v/s async. You can read the entire post on the GWT forum, I am just including the relevant analogies.

Imagine if you will ...

You are sitting on the couch watching
TV, and knowing that you are out of
beer, you ask your spouse to please
run down to the liquor store and
fetch you some. As soon as you see
your spouse walk out the front door,
you get up off the couch and trundle
into the kitchen and open the
fridge. To your surprise, there is no
beer!

Well of course there is no beer, your
spouse is still on the trip to the
liquor store. You've gotta wait until
[s]he returns before you can expect
to have a beer.

But, you say you want it synchronous? Imagine again ...

... spouse walks out the door ... now,
the entire world around you stops, you
don't get to breath, answer the
door, or finish watching your show
while [s]he runs across town to
fetch your beer. You just get to sit
there not moving a muscle, and
turning blue until you lose
consciousness ... waking up some
indefinite time later surrounded by
EMTs and a spouse saying oh, hey, I
got your beer.

That's exactly what happens when you insist on doing a synchronous server call.

夜声 2024-09-04 16:13:52

安装 Firebug,然后向每个 showLoader、updateStatus 和 hideLoader 添加如下行:

Console.log("event logged");

您将在控制台窗口中看到列出的对函数的调用,并且它们将按顺序排列。问题是你的“updateStatus”方法是做什么的?

据推测,它会启动一个后台任务,然后返回,因此您将在任何后台任务完成之前调用 hideLoader。您的 Ajax 库可能有一个“OnComplete”或“OnFinished”回调 - 从那里调用以下 updateStatus。

Install Firebug, then add a line like this to each of showLoader, updateStatus and hideLoader:

Console.log("event logged");

You'll see listed in the console window the calls to your function, and they will be in order. The question, is what does your "updateStatus" method do?

Presumably it starts a background task, then returns, so you will reach the call to hideLoader before any of the background tasks finish. Your Ajax library probably has an "OnComplete" or "OnFinished" callback - call the following updateStatus from there.

谁许谁一生繁华 2024-09-04 16:13:52

将 updateStatus 调用移至另一个函数。以新函数为目标调用 setTimeout。

如果您的 ajax 请求是异步的,您应该有一些东西来跟踪哪些请求已完成。每个回调方法都可以在某处为自己设置一个“已完成”标志,并检查它是否是最后一个这样做的方法。如果是,则让它调用 hideLoader。

move the updateStatus calls to another function. make a call setTimeout with the new function as a target.

if your ajax requests are asynchronous, you should have something to track which ones have completed. each callback method can set a "completed" flag somewhere for itself, and check to see if it's the last one to do so. if it is, then have it call hideLoader.

岛歌少女 2024-09-04 16:13:52

处理所有异步请求的最佳解决方案之一是“Promise”
Promise 对象表示异步操作的最终完成(或失败)。

示例:

let myFirstPromise = new Promise((resolve, reject) => {
  // We call resolve(...) when what we were doing asynchronously was successful, and reject(...) when it failed.
  // In this example, we use setTimeout(...) to simulate async code. 
  // In reality, you will probably be using something like XHR or an HTML5 API.
  setTimeout(function(){
    resolve("Success!"); // Yay! Everything went well!
  }, 250);
});  

myFirstPromise.then((successMessage) => {
  // successMessage is whatever we passed in the resolve(...) function above.
  // It doesn't have to be a string, but if it is only a succeed message, it probably will be.
  console.log("Yay! " + successMessage);
});

Promise

如果您有 3 个异步函数并希望按顺序运行,请执行以下操作:

let FirstPromise = new Promise((resolve, reject) => {
    FirstPromise.resolve("First!");
});
let SecondPromise = new Promise((resolve, reject) => {

});
let ThirdPromise = new Promise((resolve, reject) => {

});
FirstPromise.then((successMessage) => {
  jQuery.ajax({
    type: "type",
    url: "url",
    success: function(response){
        console.log("First! ");
        SecondPromise.resolve("Second!");
    },
    error: function() {
        //handle your error
    }  
  });           
});
SecondPromise.then((successMessage) => {
  jQuery.ajax({
    type: "type",
    url: "url",
    success: function(response){
        console.log("Second! ");
        ThirdPromise.resolve("Third!");
    },
    error: function() {
       //handle your error
    }  
  });    
});
ThirdPromise.then((successMessage) => {
  jQuery.ajax({
    type: "type",
    url: "url",
    success: function(response){
        console.log("Third! ");
    },
    error: function() {
        //handle your error
    }  
  });  
});

通过这种方法,您可以根据需要处理所有异步操作。

One of the best solutions for handling all async requests is the 'Promise'.
The Promise object represents the eventual completion (or failure) of an asynchronous operation.

Example:

let myFirstPromise = new Promise((resolve, reject) => {
  // We call resolve(...) when what we were doing asynchronously was successful, and reject(...) when it failed.
  // In this example, we use setTimeout(...) to simulate async code. 
  // In reality, you will probably be using something like XHR or an HTML5 API.
  setTimeout(function(){
    resolve("Success!"); // Yay! Everything went well!
  }, 250);
});  

myFirstPromise.then((successMessage) => {
  // successMessage is whatever we passed in the resolve(...) function above.
  // It doesn't have to be a string, but if it is only a succeed message, it probably will be.
  console.log("Yay! " + successMessage);
});

Promise

If you have 3 async functions and expect to run in order, do as follows:

let FirstPromise = new Promise((resolve, reject) => {
    FirstPromise.resolve("First!");
});
let SecondPromise = new Promise((resolve, reject) => {

});
let ThirdPromise = new Promise((resolve, reject) => {

});
FirstPromise.then((successMessage) => {
  jQuery.ajax({
    type: "type",
    url: "url",
    success: function(response){
        console.log("First! ");
        SecondPromise.resolve("Second!");
    },
    error: function() {
        //handle your error
    }  
  });           
});
SecondPromise.then((successMessage) => {
  jQuery.ajax({
    type: "type",
    url: "url",
    success: function(response){
        console.log("Second! ");
        ThirdPromise.resolve("Third!");
    },
    error: function() {
       //handle your error
    }  
  });    
});
ThirdPromise.then((successMessage) => {
  jQuery.ajax({
    type: "type",
    url: "url",
    success: function(response){
        console.log("Third! ");
    },
    error: function() {
        //handle your error
    }  
  });  
});

With this approach, you can handle all async operation as you wish.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文