javascript - 为什么同步 sleep 功能不会因为在 promise 中而变得异步?

标签 javascript asynchronous promise web-worker es6-promise

<分区>

我正在努力思考 promises,以及 JavaScript 如何使用它的队列和事件循环等。

我想如果我把一个慢速同步函数放在一个 promise 中,那个慢速同步函数就会被委托(delegate)给后台,我可以在它完成时使用 .then 来处理它。

function syncSleep(ms){
    var end = new Date().getTime() + ms;
    var start = new Date().getTime();

    while (start < end) {
      start = new Date().getTime();
    }
}

function p() {
  return new Promise(function(resolve) {
     syncSleep(5000);
     resolve("syncSleep done!");
  });
}

p().then( function(s) {
  var div = document.getElementById('async');
  div.innerHTML = s;
} );

var div = document.getElementById('sync');
div.innerHTML = "This should appear right away! (but it doesn't)";

https://jsfiddle.net/7mw6m2x5/

虽然这段代码运行时 UI 没有响应。

所以我想知道,有人可以解释这里发生了什么吗? Promises 只是一种处理已经“成为”异步代码的方法吗?

(如果是,那是怎么做到的?)

当我不希望它卡住 UI 时,如何处理慢速同步代码?我必须为此使用网络 worker 吗?

感谢任何澄清。谢谢。

最佳答案

代码按预期工作。

由于 Javascript 是单线程的,当您的循环正在执行时,UI 将被阻塞。

Promises 只是处理异步代码的好方法。在这里查看介绍:

http://www.html5rocks.com/en/tutorials/es6/promises/

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

为了能够在其他代码在后台执行时保持 UI 响应,您需要使用 WebWorkers:

https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers

引用上面列出的页面:

“Web Workers 为 Web 内容提供了一种在后台线程中运行脚本的简单方法。工作线程可以在不干扰用户界面的情况下执行任务。”

更新:

根据您的意见,我编写了这个小脚本来演示阻塞方法和非阻塞方法之间的区别。 代码中有一些重复,但我认为它足够简单易懂。

function setVal(s) {
  var divAsync = document.getElementById('async');
  var innerDiv = document.createElement('div');
  innerDiv.innerHTML = s + '<br>';
  divAsync.appendChild(innerDiv);
}


function syncSleep(ms) {
  var end = new Date().getTime() + ms;
  var now = new Date().getTime();
  var stepBegin = new Date().getTime();
  var step = 0;

  // This loop is blocking
  // The UI will only refresh after the loop completion
  while (now < end) {
    now = new Date().getTime();
    step = now - stepBegin;
    if (step >= 1000) {
      setVal(now);
      step = 0;
      stepBegin = now;
    }
  }

}

function pBlock() {
  return new Promise(function(resolve) {
    syncSleep(3200);
    resolve("pBlock syncSleep done!");
  });
}


function noBlockUpdate(ms, resolve) {
  var end = new Date().getTime() + ms;
  var now = new Date().getTime();
  var stepBegin = new Date().getTime();
  var step = 0;

  function noBlock() {
    now = new Date().getTime();

    // paint every 1000ms;
    step = now - stepBegin;
    if (step >= 1000) {
      setVal(now);
      step = 0;
      stepBegin = now;
    }

    if (now < end) {
      // NB: this is going to be called thousands of times
      // But the UI will still update every 1000 ms
      setTimeout(noBlock);
    } else {
      resolve("pNoBlock done!");
    }
  };
  noBlock();
}

function pNoBlock() {
  return new Promise(function(resolve) {
    noBlockUpdate(3200, resolve);
    setVal("pNoBlock launched!");
  });
}



pNoBlock().then(setVal);

var divSync = document.getElementById('sync');
divSync.innerHTML = "This appears right away!";



// Just wait 4 seconds so the non-blocking code completes
setTimeout(function() {
  // Clear all div's
  document.getElementById('sync').innerHTML = '';
  document.getElementById('async').innerHTML = '';

  var divSync = document.getElementById('sync');
  divSync.innerHTML = "This does not appear right away, only after the blocking operation is complete!";

  pBlock().then(setVal);
}, 4000);
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>

<body>

  <div id="sync"></div>

  <div id="async"></div>

</body>

</html>

关于javascript - 为什么同步 sleep 功能不会因为在 promise 中而变得异步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37091875/

相关文章:

javascript - IE8内存泄漏?

javascript - 使用 Node.js 如何设置 var 来响应 HTTP 客户端?

node.js - 如何在谷歌工作表中同步添加行?

JavaScript promise 执行时间

javascript - Jasny-Bootstrap 显示菜单打破了导航栏折叠和导航栏切换功能

javascript - 如何使用angularjs从数组中删除时间

c# - 如何在处理异常时异步延迟所有 future 的调用

javascript - 如何从 Unirest PUT 请求中返回一个 Promise

javascript - 如果其中一个 promise 失败,Promise.all 不会返回任何 promise

javascript - Puppeteer js eval 函数返回对象的对象