问题描述
JavaScript是单线程语言,因此它一次只执行一个命令。正在通过 Web API (用于事件处理的 DOM,用于AJAX调用的XMLHttpRequest,用于setTimeout 的WindowTimers)和事件队列来实现异步编程。由浏览器管理。到现在为止还挺好!现在考虑以下非常简单的代码:
JavaScript is a single threaded language and therefore it executes one command at a time. Asynchronous programming is being implemented via Web APIs (DOM for event handling, XMLHttpRequest for AJAX calls, WindowTimers for setTimeout) and the Event queue which are managed by the browser. So far, so good! Consider now, the following very simple code:
$('#mybox').hide(17000);
console.log('Previous command has not yet terminated!');
...
有人可以向我解释上述的基本机制吗?由于.hide()尚未完成(动画持续17秒)并且JS引擎正在处理它并且它能够一次执行一个命令,它以何种方式进入下一行并继续运行剩余代码?
Could someone please explain to me the underlying mechanism of the above? Since .hide() has not yet finished (the animation lasts 17 seconds) and JS engine is dealing with it and it is capable of executing one command at a time, in which way does it go to the next line and continues to run the remaining code?
如果您的答案是动画创建承诺,问题仍然相同:JavaScript如何同时处理多个事物(执行动画本身,在承诺的情况下观察动画队列并继续执行下面的代码......)。
If your answer is that animation creates promises, the question remains the same: How JavaScript is dealing with more than one thing at the same time (executing the animation itself, watching the animation queue in case of promises and proceeding with the code that follows...).
此外,如果他们必须观看他们的父Deferred对象,直到它被解决或被拒绝 ,这意味着代码执行,同时剩下的代码被执行。这怎么可能在单线程方法中?理解AJAX调用我没有问题,因为我知道它们被JS引擎带走了......
Moreover, I cannot explain how promises in jQuery work if they have to watch their parent Deferred object till it is resolved or rejected that means code execution and at the same time the remaining code is executed. How is that possible in a single threaded approach? I have no problem to understand AJAX calls for I know they are taken away from JS engine...
推荐答案
tl ;博士; 在没有外界帮助的情况下,在严格的单线程环境中是不可能的。
tl;dr; it would not be possible in a strictly single threaded environment without outside help.
我认为我理解你的问题。让我们先解决一些问题:
I think I understand your issue. Let's get a few things out of the way:
没有定义异步API语言规范。所有函数,如 Array.prototype.map
或 String.fromCharCode
总是同步运行*。
No asynchronous APIs are defined in the language specification. All the functions like Array.prototype.map
or String.fromCharCode
always run synchronously*.
代码将始终运行完成。代码不会停止运行,直到它被 return
终止,隐式返回
(到达代码末尾)或者抛出
(突然)。
Code will always run to completion. Code does not stop running until it is terminated by a return
, an implicit return
(reaching the end of the code) or a throw
(abruptly).
a();
b();
c();
d(); // the order of these functions executed is always a, b, c, d and nothing else will
// happen until all of them finish executing
JavaScript位于平台内
JavaScript语言定义了一个名为:
在浏览器中运行JavaScript的主机环境称为或文档对象模型。它指定浏览器窗口如何与JavaScript语言交互。例如,在NodeJS中,主机环境完全不同。
The host environment in which JavaScript is run in the browser is called the DOM or document object model. It specifies how your browser window interacts with the JavaScript language. In NodeJS for example the host environment is entirely different.
虽然所有JavaScript对象和函数同步运行完成 - 主机环境可能会暴露自己的功能,但不一定用JavaScript定义。它们没有标准JavaScript代码所具有的相同限制,可能会定义不同的行为 - 例如 document.getElementsByClassName
的结果是一个实时DOM 与普通JavaScript代码的行为截然不同:
While all JavaScript objects and functions run synchronously to completion - the host environment may expose functions of its own which are not necessarily defined in JavaScript. They do not have the same restrictions standard JavaScript code has and may define different behaviors - for example the result of document.getElementsByClassName
is a live DOM NodeList
which has very different behavior from your ordinary JavaScript code:
var els = document.getElementsByClassName("foo");
var n = document.createElement("div");
n.className = "foo";
document.body.appendChild(n);
els.length; // this increased in 1, it keeps track of the elements on the page
// it behaves differently from a JavaScript array for example.
其中一些主机功能必须执行I / O操作,如计划定时器,执行网络请求或执行文件访问。像所有其他API 一样,这些API必须运行完成。这些API由主机平台提供 - 它们调用您的代码所没有的功能 - 通常(但不一定)它们是用C ++编写的,并使用线程和操作系统工具同时运行平行。这种并发可以只是后台工作(比如安排一个计时器)或实际的并行性(比如 - 再次成为DOM的一部分,而不是JavaScript)。
Some of these host functions have to perform I/O operations like schedule timers, perform network requests or perform file access. These APIs like all the other APIs have to run to completion. These APIs are by the host platform - they invoke capabilities your code doesn't have - typically (but not necessarily) they're written in C++ and use threading and operating system facilities for running things concurrently and in parallel. This concurrency can be just background work (like scheduling a timer) or actual parallelism (like WebWorkers - again part of the DOM and not JavaScript).
因此,当您调用DOM上的操作(如setTimeout)或应用导致CSS动画的类时,它不会受到代码所具有的相同要求的约束。它可以使用线程或操作系统。
So, when you invoke actions on the DOM like setTimeout, or applying a class that causes CSS animation it is not bound to the same requirements your code has. It can use threading or operating system async io.
当您执行以下操作时:
setTimeout(function() {
console.log("World");
});
console.log("Hello");
实际发生的是:
- 使用类型为function的参数调用主机函数
setTimeout
。它将该功能推送到主机环境中的。 - 同步执行
console.log(Hello)
。 - 运行所有其他同步代码(注意,这里的setTimeout调用是完全同步的。)。
- JavaScript完成运行 - 控制权转移到主机环境。
- 主机环境通知它在定时器队列中有一些东西,并且已经过了足够的时间,所以它调用它的参数(函数) -
console.log(World)
被执行。 - 该函数中的所有其他代码同步运行。
- 控制权返回主机环境(平台)。
- 在主机环境中发生了其他事情(鼠标单击,返回AJAX请求,定时器触发)。主机环境调用用户传递给这些操作的处理程序。
- 同样,所有JavaScript都是同步运行的。
- 依此类推...... 。
- The host function
setTimeout
is called with a parameter of type function. It pushes the function into a queue in the host environment. - the
console.log("Hello")
is executed synchronously. - All other synchronous code is run (note, the setTimeout call was completely synchronous here).
- JavaScript finished running - control is transferred to the host environment.
- The host environment notices it has something in the timers queue and enough time has passed so it calls its argument (the function) -
console.log("World")
is executed. - All other code in the function is run synchronously.
- Control is yielded back to the host environment (platform).
- Something else happens in the host environment (mouse click, AJAX request returning, timer firing). The host environment calls the handler the user passed to these actions.
- Again all JavaScript is run synchronously.
- And so on and so on...
$('#mybox').hide(17000);
console.log('Previous command has not yet terminated!');
此处代码同步运行。上一个命令已已终止,但实际上没有做太多 - 而是在平台上安排了回调a(在 .hide(17000)
然后再次执行 console.log
- 所有JavaScirpt代码始终同步运行。
Here the code is run synchronously. The previous command has terminated, but it did not actually do much - instead it scheduled a callback on the platform a(in the .hide(17000)
and then executed the console.log
since again - all JavaScirpt code runs synchronously always.
即 - 隐藏执行很少的工作并运行几毫秒,然后安排更多工作稍后完成。它不运行17秒。
That is - hide performs very little work and runs for a few milliseconds and then schedules more work to be done later. It does not run for 17 seconds.
现在hide的实现类似于:
Now the implementation of hide looks something like:
function hide(element, howLong) {
var o = 16 / howLong; // calculate how much opacity to reduce each time
// ask the host environment to call us every 16ms
var t = setInterval(function
// make the element a little more transparent
element.style.opacity = (parseInt(element.style.opacity) || 1) - o;
if(parseInt(element.style.opacity) < o) { // last step
clearInterval(t); // ask the platform to stop calling us
o.style.display = "none"; // mark the element as hidden
}
,16);
}
基本上我们的代码是单线程的 - 它要求平台调用它60每秒一次,使元素每次都不那么明显。一切都在运行完成,但除了第一个代码执行之外,平台代码(主机环境)正在调用我们的代码,反之亦然。
So basically our code is single threaded - it asks the platform to call it 60 times a second and makes the element a little less visible each time. Everything is always run to completion but except for the first code execution the platform code (the host environment) is calling our code except for vice versa.
因此,对您的问题的实际直接答案是,计算的时间从代码中消失,就像您发出AJAX请求时一样。直接回答:
So the actual straightforward answer to your question is that the timing of the computation is "taken away" from your code much like in when you make an AJAX request. To answer it directly:
外部是封闭系统,它使用线程或操作系统异步设施 - 我们的主机环境。在纯标准ECMAScript中没有它就无法完成。
That outside is the enclosing system that uses either threads or operating system asynchronous facilities - our host environment. It could not be done without it in pure standard ECMAScript.
这篇关于单线程JavaScript下的动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!