【提案讨论】JavaScript 异步上下文 #9
Replies: 8 comments
-
提案中的描述不是特别清晰,我想问一下,是否可能有多个上下文同时进行,例如 startAsyncTask1(asyncTask) // Inner async tasks will use the context 1
startAsyncTask1(asyncTask) // Inner async tasks will use the context 2 另外 |
Beta Was this translation helpful? Give feedback.
-
在一个时刻内运行的 JavaScript 上下文肯定只有一个,而这个上下文的逻辑异步上下文链接也只有一个。
所有涉及到 Host 环境提供的异步操作(有些称呼为 macro task),与 micro task 都应该算作异步操作,在这些任务加入任务队列时,就需要创建异步上下文链接。 |
Beta Was this translation helpful? Give feedback.
-
最好能有点代码示例,大家会比较容易理解。(目前提案里虽然有一点儿代码,但感觉解释有点不足。比如AsyncLocal的enterWith语义——因为这个东西感觉上是有magic的,就需要解释得详细点。) |
Beta Was this translation helpful? Give feedback.
-
如果是指同一个 asyncLocalStorage 是否可以在多个异步上下文中使用的话,我们可以看下面这个例子: const asyncLocalStorage = new AsyncLocalStorage()
asyncLocalStorage.enterWith(1)
setTimeout(() => {
console.log('a', asyncLocalStorage.getStore()) // => 1
setTimeout(() => {
console.log('a -> a', asyncLocalStorage.getStore()) // => 1
}, 1)
}, 1)
setTimeout(() => {
console.log('b', asyncLocalStorage.getStore()) // => 1
}, 1)
asyncLocalStorage.enterWith(2)
setTimeout(() => {
console.log('c', asyncLocalStorage.getStore()) // => 2
}, 1) AsyncLocalStorage 可以看作比较常见的 ThreadLocal。ThreadLocal 是一个访问器,在不同的线程中访问会访问到对应线程的数据上,各个线程间这个数据不会互相干扰。AsyncLocalStorage 也是类似的,在不同的异步上下文中访问只会访问到当前异步上下文中的数据。 |
Beta Was this translation helpful? Give feedback.
-
我估计是比较像ThreadLocal,不过现在这个API和ThreadLocal还是不太一样,不知道开发者是否能正确理解。尤其是如何建立一个容易接受的概念模型来解释其所具有的某些magic特征。 看了例子,我猜想应该对于所有的异步都有效? 比如应该可以 const als = new AsyncLocalStorage()
const listenClick = () => {
window.addEventListener('click', () => {
console.log(als.getStore())
})
}
als.enterWith(1)
listenClick()
als.enterWith(2)
listenClick()
// 点击一下应会输出 1 和 2? 这可能需要浏览器也使用类似 async hooks 的机制? 另外一个小问题,感觉上 |
Beta Was this translation helpful? Give feedback.
-
是的,对于所有的异步都有效。 其实现在有几个问题,包括现在的Node.js实现与Zones提案都没有比较好的方案的是:
目前我的想法是可以将上面说的三方的使用场景都切分开来,除了提供 Node.js 目前实验性的 AsyncResource(”提供异步控制流的库“) 与 AsyncLocalStorage (”AsyncLocal“)的类似的方案,还需要将 Zone 中揉杂的概念理清并使用AsyncResource 与 AsyncLocal代替,然后提供一个新的方案供”提供异步逻辑流的框架“声明异步逻辑流。
比如下面这个例子: const asyncLocal = new AsyncLocal(() => /** defaultValue */ 1);
asyncLocal.value = 2
http.createServer((req, res) => {
asyncLocal.value // 2, still in root async flow
AsyncFlow.new(() => {
asyncLocal.value // 1, initialized to default value
})
}) 例子中在进入了 http server 的 incoming message 处理后,还是保持着原来的异步逻辑流,因为需要显示声明新的异步逻辑流,就像线程需要显示创建一样。而 AsyncLocal 就可以提供与其他语言中的 ThreadLocal/AsyncLocal 类似的语义与 API。 而像 bluebird 等提供异步控制流的库,不应该使用 |
Beta Was this translation helpful? Give feedback.
-
上次没过,本次会议有什么更新计划? |
Beta Was this translation helpful? Give feedback.
-
这次主要是根据6月份会议上的顾虑与意见修改了提案的方案,比如通过限制了触发条件的值变化监听来代替 AsyncHooks 的能力,触发这个监听需要直接引用对应的 AsyncLocal 实例,而且触发的时间点也是用户显式调用的时间点,解决安全性的顾虑。AsyncHooks 的能力还是交给 Host 平台比如 Node.js 来自行决定实现方案。 |
Beta Was this translation helpful? Give feedback.
-
提案仓库:https://github.com/legendecas/proposal-async-context
在与 Node.js Diag WG 讨论后,我们决定在 6 月份的会议中提议 JavaScript 异步上下文提案演进到 Stage 1。这个提案的前身是之前被放弃的 Zones 提案,不过 Zones 提案的 Champion 期望能够在异步上下文中集成异常处理、异步任务拦截等操作,这些操作在设计上非常容易引起隐式行为,比如未被处理的异常被错误噤声等情况。因为 Node.js 在这方面有 Domain 模块因为这些隐式行为而废弃的经验,所以部分 Node.js 中在相关方面有较多投入的人提出了异议。
这次我们重新提议这个提案,主要是为了能够在实现了 async/await 等异步操作的 JavaScript 中,在不改变当前异步任务行为的情况下,引入如 AsyncLocal,异步操作追踪(AsyncHooks)等内置对象与操作。
Beta Was this translation helpful? Give feedback.
All reactions