Javascript Promises库在浏览器中制作“长时间运行代码 - 非阻塞UI”?

时间:2013-12-17 09:25:59

标签: javascript asynchronous nonblocking promise

更新

这是对以下问题的更新,应该有助于找到答案

接受torazaburo的答案,他还引用了部分杰出的Javascript承诺/ A +定义,我想在此更新问题。
Promise/A+规范在第2.2.4点建议:

  在执行之前,不得调用onPulfilled或onRejected   上下文堆栈仅包含平台代码。 3.1。

并进一步解释

  

这里的“平台代码”意味着引擎,环境和承诺   实施代码。在实践中,这个要求确保了这一点   在事件发生后,onFulfilled和onRejected异步执行   循环转入然后调用,并使用新堆栈。这可以   使用“宏任务”机制(如setTimeout或)实现   setImmediate,或者使用“微任务”机制   MutationObserver或process.nextTick。自承诺实施以来   被认为是平台代码,它本身可能包含任务调度   队列或“trampoline”,其中调用处理程序。

我期待在这个问题上找到的问题是,Promise实现Javascript代码本身被认为是平台代码的关键点,并且允许不通过事件循环来解决后续的承诺调用相关的onFulfilled onRejected个函数。这在Node.js(服务器)中是很好的,因为它避免了回到事件循环(离开执行堆栈)的不必要的回归,但也导致浏览器中的挑战,因为执行堆栈不是在解决潜在的大量Promise之间退出(它们本身可以生成新的Promises)。不离开执行堆栈并屈服于事件循环会导致浏览器出现意外(阻塞脚本警告/问题)。 "蹦床" Promise实现的任务调度导致这种需要,但是不必避免不时地将执行交还给Javascript事件循环。这样的功能允许将Promise用于较重的任务。 Promises for" long-running-code"在这个问题中搜索/要求。

澄清:过度长度"不是onFulfilled函数的个体长度,而是由于Promise解析过程(当以这样的" trampoline"方式完成)将几个函数/回调连接在一起。我已经意识到,如果一个人onFulfilled函数太长,那么通过使用任何类型的Promise实现都不会有任何帮助。

这里的交易是x promises的后续解析(在一个执行堆栈中,因此没有回到Javascript事件循环)可能会导致Javascript代码执行的持续时间过长。这在浏览器中很糟糕(因为阻塞)。

问题

在Javascript中,Promises允许处理异步编程任务。太好了!

已经有一些实现和库围绕QWinJSwhen.js来命名。 看了之后,我发现他们已经解决了一些特殊问题"在Javascript异步编程中挑战。

通常我认为他们为承诺解决方案

执行此操作
  1. 转到承诺的内部列表
  2. 检查承诺是否已满,并运行所有相关(通过then(onFullfilled,onReject))功能。
  3. (在某些情况下,我们在这里完成)
  4. (在其他情况下,仍有"待定"承诺)
  5. 这种情况(4)是因为让它们(其余的承诺)满了将需要当前的Javascript代码(这是承诺解析的代码)停止运行并允许JS {{ 1}}发生(即XHR请求或User-UI交互等异步事件)。为了使这个(4)工作,承诺解决方案正常安排召回(即通过setTimeout / setImmediate)并在event loop运行后继续,因此可能会有一些"等待& #34;承诺已经解决(=拒绝/已满)。

    我担心的是,第1步和第2步可能会运行很长一段时间,只有在event loop执行时才会执行,以防它似乎已经解决了某些"待定"承诺。虽然"好的"在某些情况下(即在服务器/ Node.js上),在浏览器中存在很大问题,因为即使将执行释放到event loop并且UI没有阻塞也没有问题,但这并没有完成在我所见过的承诺的实施中。

    因此,我的问题是: 你知道一个关心方面的promise实现(Javascript Promises库):
    制作"长期运行代码 - 非阻塞UI"在浏览器中?

    这意味着承诺解析会自动将执行释放回event loop,以便CSS动画,用户输入,鼠标交互确实得到足够的关注,并且没有"警告:无响应的脚本"消息。

2 个答案:

答案 0 :(得分:2)

任何兼容的promises实现都不会同步运行then函数,而只会在下一个tick处运行。因此,您担心“第1步和第2步可能会运行很长一段时间”是没有根据的。

来自Promises / A +规范:

  在执行上下文堆栈仅包含平台代码之前,不得调用

onFulfilledonRejected

     

此处“平台代码”表示引擎,环境和承诺实现代码。在实践中,此要求确保onFulfilledonRejected异步执行,然后在调用事件循环之后执行,并使用新堆栈。

换句话说,2)中的配方不正确。 promises实现不会“运行相关的函数”,它计划它们。

如果处理程序本身是“长时间运行”的代码,这对你无能为力 - 实际上没有办法帮助你。

答案 1 :(得分:0)

我认为解决方案可能是解析长期运行的JavaScript代码,例如使用https://github.com/NeilFraser/JS-Interpreter

它会使代码更慢,但您可以指定优先级:

const myInterpreter = new Interpreter(myCode);
function nextStep() {
    if (myInterpreter.step()) {
        window.setTimeout(nextStep, 100/speed);
    }
}
nextStep();