为什么foo和bar都是平行的?

时间:2017-04-20 07:43:31

标签: javascript

根据You-Dont-Know-JS 非交互

var res = {};

function foo(results) {
    res.foo = results;
}

function bar(results) {
    res.bar = results;
}

// ajax(..) is some arbitrary Ajax function given by a library
ajax( "http://some.url.1", foo );
ajax( "http://some.url.2", bar );

foo()bar()是两个concurrent个“进程”,并且它是不确定的,它们将被触发的顺序。但我们已经构建了程序,因此无关紧要命令他们开火,因为他们独立行动,因此不需要互动。

我无法理解 concurrent 的意思。

我知道JavaScript是单线程。为什么foobar是两个concurrent“流程

2 个答案:

答案 0 :(得分:1)

我认为他们是"并发" (这是一个混乱的imo)因为ajax()函数使它们异步,它们就像一个回调函数一样成为一个promise,所以它将取决于它们在参数中到达地址的速度并返回一个值。

编辑:一点点绘图以防它可以帮助:-) 同时触发2条指令,但因为它们是异步的,所以执行2 ajax调用之下的指令而不等待返回值

enter image description here

这里,第一个请求需要300毫秒才能返回状态200'的响应对象。 (粗略地foo = 200)而在第二个请求中,返回404并将其分配给bar变量需要两倍的时间。

如果你想等第一个ajax调用在返回第二个之前返回一些东西,你需要检查js中的Promises,你在那里做<div class="main"> <div class="fcard"> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. </div> <div class="scard"> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco . </div> </div>之类的事情(严重再次)

答案 1 :(得分:0)

多线程和并发是相关的,但不相同。相反,多线程是我们可以将并发引入程序的方法之一。但肯定不是唯一的方式。

在您的情况下,引入的并发性不是来自多线程,而是来自异步ajax调用(这就是 ajax 的含义 - 它是“异步”的缩写Javascript和XML“,而不是用于执行在ajax之前使用的后台请求的同步方法”。 Javascript仍然在单线程上执行,但是该单个线程可以替代地用于处理多个不同的请求。它只需要在有代码执行时执行 - 并且ajax调用已经返回,就像它的调用者一样。自Apple Macintosh以来一直是GUI编程主要的消息循环范例就是这样做的一种方式。

让我们假装你正在尝试用Javascript编写一个多任务的多任务操作系统。为简单起见,我们假设所有I / O都需要定期轮询(真实计算机如何工作 - 它们使用DMA和中断来完成比线程低得多的请求)。假设我们有两个应用程序;一个正在等待键盘的用户输入,另一个正在等待计时器:

function appQuery() {
  while (true) {
    var input = readUserInput();

    console.log("User input: " + input);
  }
}

function appTimer() {
  while (true) {
    wait(10);

    console.log("Timer tick!");
  }
}

我们如何允许这两个应用程序“同时”运行?大多数情况下,应用程序都不需要任何CPU,因此它可能只是在后台“等待”,直到满足它们的I / O请求(分别通过键盘按下或计时器滴答)。我们如何实现readUserInputwait来“阻止”应用程序,而不“阻止”整个系统?事实证明,有很多方法。

Javascript中最简单的方法是使用continuation。也就是说,我们不是使用简单的同步(或同步查看)代码,而是使用“之后发生的事情”明确地安排每个异步任务。你可能已经使用过了 - 这是setTimeoutajax的工作方式。 setTimeout方法立即终止,但作为参数传递的函数仅在超时通过后执行。

对于我们的情况,代码可能如下所示:

function appQuery() {
  var action = {};
  action = function(input) {
    output.innerText += "User input: " + input + "\r\n";

    actOnUserInput(action);
  }

  actOnUserInput(action);
}

function appTimer() {
  var action = {};
  action = function() {
    output.innerText += "Timer tick!\r\n";

    actOnTimer(10, action);
  }

  actOnTimer(10, action);
}

现在appQueryappTimer都会立即返回,而不是等待输入或计时器。如果您想要一个具有多个等待的工作流,您只需在“序列”中使用多个延续。但是我们如何确保他们在合适的时刻执行他们的行动呢?一个简单的方法是使用一个主循环来跟踪多个任务,并在等待条件完成后立即在它们之间切换:

var tasks = [];

function mainLoopBody() {
  var taskCount = tasks.length;
    for (var i = 0; i < taskCount; i++) {
    var task = tasks[i];

    if (task.condition()) { // Is the request ready?
      tasks.splice(i, 1);   // 
      task.action();
      i--;
      taskCount--;
    }
  }
}

actOnXXX函数非常简单 - 它们只是将任务附加到任务队列:

function actOnUserInput(action) {
  tasks.push({ 
    condition: function() { return currentInput !== noInput; }, 
    action: function () { action(readUserInput()); } 
  });
}

function actOnTimer(timeInSeconds, action) {
    var startTime = Date.now();

  tasks.push({ 
    condition: function() { return startTime + (timeInSeconds * 1000) <= Date.now(); }, 
    action: function () { action(); } 
  });
}

现在,如果我们实际在控制台应用程序中运行它,我们所要做的只是while (true) mainLoopBody();。但由于我们在具有自己的消息循环的GUI应用程序中,我们需要使用不同的方法:

appQuery(); // Schedule query app
appTimer(); // Schedule timer app

setInterval(mainLoopBody, 100); // Run the OS!

setInterval基本上告诉浏览器的消息循环,偶尔给我们的消息循环一次机会;在真实的计算机中,这大致对应于CPU计时器中断(这也是pre -mpmptive multi-tasking的工作方式)。

为了把一切都搞定,我们仍然需要给自己一个生活的页面:

<input id="userInput" />
<button onclick="setInput();">OK</button>

<div id="output" />

最后,我们的假装输入缓冲区(在典型的单线程,无GUI系统,如MS-DOS,这将粗略对应于输入中断处理程序):

var noInput = {};
window.currentInput = noInput;

window.setInput = function() {
  if (currentInput !== noInput) return; // We only allow one input in the buffer

  currentInput = userInput.value;
  userInput.value = '';
}

function readUserInput() {
  var input = currentInput;
  currentInput = noInput;
  return input;
}

而且你有它 - 两个“有用的”应用程序在单线程上并发运行,你可以同时运行它们中的任意数量(当然,直到你的CPU或内存耗尽)。从来没有一个应用程序同时使用CPU,但大多数应用程序不需要那么多的CPU - 你通常都在等待某种I / O.

如果您有兴趣,可以使用https://jsfiddle.net/sjy0mgy7/1/上的完整示例:)