Unk*_*per 7 javascript single-threaded jquery-animate
JavaScript是单线程语言,因此它一次只执行一个命令.异步编程通过Web API(用于事件处理的DOM,用于AJAX调用的XMLHttpRequest,用于setTimeout的WindowTimers)和由浏览器管理的事件队列来实现.到现在为止还挺好!现在考虑一下,以下非常简单的代码:
$('#mybox').hide(17000);
console.log('Previous command has not yet terminated!');
...
Run Code Online (Sandbox Code Playgroud)
有人可以向我解释上面的基本机制吗?由于.hide()还没有完成(动画持续17秒)并且JS引擎正在处理它并且它能够一次执行一个命令,它以哪种方式进入下一行并继续运行剩下的代码?
如果您的答案是动画创建了promises,那么问题仍然是:JavaScript如何同时处理多个事物(执行动画本身,在承诺的情况下观察动画队列并继续执行下面的代码). ..).
此外,我无法解释jQuery中的promises如何工作,如果他们必须观察他们的父Deferred对象,直到它被解析或拒绝 ,这意味着代码执行,同时执行剩余的代码.这怎么可能在单线程方法中?理解AJAX调用我没有问题,因为我知道它们被JS引擎带走了......
Ben*_*aum 20
TL;博士; 没有外界帮助,在严格的单线程环境中是不可能的.
我想我理解你的问题.让我们先解决一些问题:
语言规范中未定义异步API.所有功能类似Array.prototype.map或String.fromCharCode始终同步运行*.
代码将始终运行完成.代码在被a return,隐式return(到达代码的末尾)或throw(突然)终止之前不会停止运行.
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
Run Code Online (Sandbox Code Playgroud)
JavaScript语言定义了一个称为主机环境的概念:
以这种方式,据说现有系统提供对象和设施的主机环境,这完成了脚本语言的功能.
在浏览器中运行JavaScript的主机环境称为DOM或文档对象模型.它指定浏览器窗口如何与JavaScript语言交互.例如,在NodeJS中,主机环境完全不同.
虽然所有JavaScript对象和函数同步运行完成 - 主机环境可能会公开自己的函数,这些函数不一定在JavaScript中定义.它们没有标准JavaScript代码所具有的相同限制,并且可能定义不同的行为 - 例如,document.getElementsByClassName实时DOM 的结果与NodeList普通JavaScript代码具有非常不同的行为:
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.
Run Code Online (Sandbox Code Playgroud)
其中一些主机功能必须执行I/O操作,如计划定时器,执行网络请求或执行文件访问.像所有其他API一样,这些API 必须运行完成.这些API由主机平台提供 - 它们调用您的代码所没有的功能- 通常(但不一定)它们是用C++编写的,并使用线程和操作系统工具同时并行地运行.这种并发可以只是后台工作(如调度计时器)或实际并行性(如WebWorkers - 再次成为DOM的一部分,而不是JavaScript).
因此,当您像调用setTimeout一样调用DOM上的操作,或者应用导致CSS动画的类时,它不会受到代码所具有的相同要求的约束.它可以使用线程或操作系统async io.
当你做类似的事情时:
setTimeout(function() {
console.log("World");
});
console.log("Hello");
Run Code Online (Sandbox Code Playgroud)
实际发生的是:
setTimeout类型的参数调用host 函数.它将函数推送到主机环境中的队列中.console.log("Hello")被同步执行.console.log("World")被执行.$('#mybox').hide(17000);
console.log('Previous command has not yet terminated!');
Run Code Online (Sandbox Code Playgroud)
这里的代码是同步运行的.上一个命令已经终止,但它实际上没有做太多 - 而是它在平台上安排了一个回调(在.hide(17000)然后再执行console.log- 所有JavaScirpt代码始终同步运行).
也就是说 - hide执行很少的工作并运行几毫秒,然后安排更多的工作稍后完成.它不是 17秒运行.
现在hide的实现看起来像:
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);
}
Run Code Online (Sandbox Code Playgroud)
所以基本上我们的代码是单线程的 - 它要求平台每秒调用60次并使元素每次都不那么明显.一切都始终完成,但除了第一个代码执行之外,平台代码(主机环境)正在调用我们的代码,反之亦然.
因此,对您的问题的实际直接答案是,计算的时间被"从您的代码中"带走,就像您发出AJAX请求时一样.直接回答:
外部是封闭系统,它使用线程或操作系统异步设施 - 我们的主机环境.没有它在纯标准ECMAScript中就无法完成.
*随着ES2015包含promises,语言将任务委托回平台(主机环境) - 但这是一个例外.
| 归档时间: |
|
| 查看次数: |
1003 次 |
| 最近记录: |