【问题标题】:setTimeout vs normal function execution in JavascriptsetTimeout 与 Javascript 中的正常函数执行
【发布时间】:2016-02-18 20:38:48
【问题描述】:

在我的应用程序中,我有一个submitSuccesscallback 函数,它会在提交成功时从我自己的JS 库中触发。 在submitSuccesscallback中,我首先展示了一个加载器并做一些初始化操作。

function submitSuccesscallback(){
  showLoadingIndicator(); // has code a display loader
  doSubmitSuccessOperations();// has code to do some app specific operations
}

这里doSubmitSuccessOperations() 需要大约 5 秒才能完成执行。

现在我的问题是上面的代码在我得到submitSuccesscallback() 后的 5 秒内不显示加载程序(即 UI 从 showLoadingIndicator() 更改)。

如果我像下面这样更改 submitSuccesscallback(),我可以在触发 submitSuccesscallback() 后立即看到加载程序。

 function submitSuccesscallback(){
  showLoadingIndicator(); // has code a display loader
  setTimeout(doSubmitSuccessOperations, 1000);
}

现在我想知道的是:

  1. setTimeout 是否让我的doSubmitSuccessOperations() 在后台运行?

  2. 我明显感觉到doSubmitSuccessOperations()在阻塞UI操作,JS中有没有UI线程和后台线程的概念?

  3. 上述setTimeout 的任何其他替代方案?

【问题讨论】:

  • setTimeout 为您的代码提供了足够的时间来更新 DOM。是什么导致了其他功能的锁定?我猜是一个巨大的循环。
  • ^ 或 async: false AJAX 请求。
  • @epascarello 即使指定了 setTimeout(doSubmitSuccessOperations, 10);它工作正常。
  • @vrs 那是因为您实际上正在做的是在另一个线程中运行 doSubmitSuccessOperations 函数。 setTimeout(fn, 0); 也可以。
  • 在现代浏览器中 5 秒的处理时间是 巨大的 时间。这段代码到底在做什么?

标签: javascript jquery asynchronous javascript-objects dom-events


【解决方案1】:

setTimeout 是否让我的 doSubmitSuccessOperations() 在后台运行?

没有。 JS 是单线程的。代码渲染在同一个线程中。这就是为什么长时间运行的操作会阻塞渲染。

setTimeout 所做的是搁置该操作,直到引擎可以执行它(它不会停止正在运行的代码)并且至少(而不是完全)在您指定的延迟之后。正常执行之后出现的代码,就好像它是线程中的下一个操作一样。这意味着setTimeout 中的代码已经与您的代码中出现的顺序不同。

我明显感觉到doSubmitSuccessOperations()阻塞了UI操作,JS中有没有UI线程和后台线程的概念?

上面的 setTimeout 还有其他替代方法吗?

异步编程就是其中之一,计时器(setTimeout 和朋友)是最可用的。在其他环境下,IE 有setImmediate,Node 有process.nextTick。还有更接近真实线程的 WebWorkers。如果你有一个服务器,你可以使用 AJAX(也是异步操作的一种形式)调用一个服务器,让它为你做操作。

Here's a video that explains how the event loop works。视频中间的某处解释了how setTimeout schedules your callbacks

【讨论】:

    【解决方案2】:

    基本上,您有一个 JavaScript 引擎在浏览器中运行您的代码。这个引擎有一个调用栈。它是您排队等待执行的所有函数的堆栈。还有一个叫做事件循环的东西,它是一个队列,其中包含作为某些事件的副作用排队的函数。当调用堆栈为空时,放在事件循环顶部的函数被压入调用堆栈并被执行。此调用堆栈位于您的 UI 线程“内部”。

    当你调用 setTimeout(doSubmitSuccessOperations, 1000); doSubmitSuccessOperations 在这行代码执行后 1 秒被添加到事件循环中。当你的所有 UI 逻辑被执行(显示微调器、移动文本、动画等)时,调用堆栈将为空。然后 doSubmitSuccessOperations 将从事件循环中弹出并推入调用堆栈。这是函数被执行的时候。

    所以,不,setTimeout 不会让 doSubmitSuccessOperations 在后台运行。它只是让它在你的 UI 逻辑之后运行。

    后台线程有一个概念,它被称为服务工作者。但是你不能在里面做UI操作。

    【讨论】:

      【解决方案3】:

      1) setTimeout 是否让我的 doSubmitSuccessOperations() 在后台运行? - 没有

      2) 我明显感觉到doSubmitSuccessOperations() 阻塞了UI 操作,JS 中有没有UI 线程和后台线程的概念? - 没有

      3) 上述 setTimeout 的任何其他替代方案? - 您可以尝试将超时设置为 0,这样引擎将尝试在第一个可用位置执行该函数。

      【讨论】:

        【解决方案4】:

        您在第三个查询的其他答案中解释的所有查询您可以使用回调模式来显示加载图像它会起作用您可以尝试 而不是这个

        function submitSuccesscallback(){
            showLoadingIndicator(); // has code a display loader
            doSubmitSuccessOperations();// has code to do some app specific operations
          }
        

        类似

        submitSuccesscallback(function(){
          showLoadingIndicator(function(){
          doSubmitSuccessOperations()
          })
        })
        

        而您的其他函数必须处理类似

        的回调
        function showLoadingIndicator(callback){
        // your code to display loading image
         $('loadingimage').show(0,'', function(){
            callback();
        });
        
        }
        
        function submitSuccesscallback(callback){
            // your code must be sync here 
            // if asynchrony than call callback in .success function
        
           //at last(if no asyn operation)
           callback()
        
          }
        

        【讨论】:

          猜你喜欢
          • 2018-03-11
          • 2016-07-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多