- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我对现代JavaScript(ES8)有点陌生。异步产生的首选方法是什么,即使用await
在事件循环的某些将来迭代中继续执行脚本?我看到了以下选项:
async function yield1() {
await Promise.resolve();
console.log("done");
}
async function yield2() {
// setImmediate is non-standard, only Edge and Node have it
await new Promise(done => (setImmediate? setImmediate: setTimeout)(done));
console.log("done");
}
async function yield3() {
await new Promise(done => setTimeout(done));
console.log("done");
}
propertyChanged
事件。这是一个完整的示例,“产量”部分位于
firePropertyChanged
内:
const EventEmitter = require('events');
class Model extends EventEmitter {
constructor(data) {
super();
this._data = data;
}
get data() {
return this._data;
}
set data(newValue) {
const oldValue = this._data;
if (oldValue !== newValue) {
this._data = newValue;
this.firePropertyChanged('data', newValue, oldValue);
}
}
async firePropertyChanged(property, newValue, oldValue) {
await Promise.resolve().then(() =>
super.emit('propertyChanged', { target: this, property, newValue, oldValue }));
console.log('all propertyChanged handlers have been called asynchronously');
}
}
async function waitForChange(obj) {
await new Promise(resolve =>
obj.once('propertyChanged', args =>
console.log(`propertyChanged: ${args.property}, ${args.oldValue} -> ${args.newValue}`)));
}
async function test() {
const obj = new Model("old");
var change = waitForChange(obj);
console.log(`before change: ${obj.data}`);
obj.data = "new";
console.log(`after change: ${obj.data}`);
await change;
}
test().catch(e => console.error(e));
propertyChanged
的setter方法返回给调用方之前调用
data
的任何事件处理程序。
最佳答案
好的,我会在您的评论中讨论您的问题的新摘要(您可能应该编辑您的问题,这样说):
我想以最有效的方式在事件循环的将来迭代中运行一段代码(并让当前方法返回)。没有特别的偏好,但是连续的顺序应该很重要。例如,在我的示例中,如果property1更改了,那么property2更改了,我首先要为property1然后为property2触发propertyChanged(在两种情况下,都与更改了两个属性的代码异步)。
简短的版本是您可以使用下面的几乎任何选项来解决您的问题。在不了解您的特定情况/要求的情况下,我可能会建议您使用setImmediate()
,因为如果递归触发它不会饿死事件队列,但是如果process.nextTick()
或Promise.resolve().then()
会在(其他类型的事件之前)触发得更快一些。对您的来电者很重要。
这是每种选择的一些解释-每个选择都可能实现您的目标,但是每个细节都有所不同。
所有这些选项都允许事件循环的当前滴答声结束,然后它们计划在事件循环的将来滴答声中调用回调。它们的确切区别在于何时调用下一个回调,并且根据当前正在处理的事件类型(例如,事件循环在扫描几个不同事件队列的过程中的位置)安排下一个回调时,它们会有所不同。
您可以先阅读本概述文章The Node.js Event Loop, Timers, and process.nextTick()
process.nextTick(cb)
这是安排回调的最快方法。事件循环的当前滴答声完成了执行,然后在node.js事件循环代码查看事件循环中的任何其他事件队列之前,它先查找nextTickQueue
中的项目并运行它们。注意,如果您连续递归调用process.nextTick()
,则可能会“饿死”事件循环,因为在nextTickQueue
为空之前,它不会给其他事件提供运行的机会。这不是一个“公平的”调度程序。
setImmediate(cb)
这计划在事件循环的当前“阶段”完成后运行回调。您可以将事件循环视为遍历许多不同类型的队列。当前正在处理的队列类型为空时,将处理所有未决的setImmediate()
回调。
请注意,这与其他类型的事件有何关系,然后取决于调用setImmediate()
时正在处理的事件类型。
例如,如果您处于fs.read()
的完成回调中,并且调用setImmediate()
安排了回调,那么事件循环将首先处理所有其他未决的I / O事件,然后再处理setImmediate()
回调。因为只有在事件循环前进到事件队列中的下一个事件类型时,它才被调用,所以您不能使setImmediate()
饿死事件循环。即使递归调用setImmediate()
仍会循环遍历所有事件。
相对于您计划的setTimeout()
如何处理待处理的setImmediate()
取决于您调用setImmediate()
时处于事件循环的哪个阶段。通常,这超出了代码中应注意的范围。如果像这样的多个异步操作的相对计时很重要,那么编写保证给定序列的代码要安全得多,而不管它们的回调何时启用它们。承诺可以帮助您对此类事情进行排序。
setTimeout(cb,0)
计时器是事件循环的一个阶段。在围绕事件循环查看不同类型的事件队列时,阶段之一是查找时间已过去的所有计时器事件,因此该调用它们的回调了。由于此计时器仅在事件循环处于“计时器阶段”时才运行,因此它们相对于其他类型的事件的触发方式不确定。当计时器准备就绪时,取决于事件循环在其循环中的位置。就我个人而言,除非我试图与其他计时器事件进行同步,否则我通常不使用setTimeout(cb, 0)
,因为这将保证与其他计时器事件(而非其他类型的事件)的FIFO顺序。
Promise.resolve()。then(cb)
为了达到承诺的详细级别(通常不需要),您必须非常清楚所使用的promise实现是什么以及它如何工作。非本机代码承诺实现将使用其他计时机制之一来调度其.then()
处理程序。它们中的任何一个都可以适当地满足Promise规范,因此它们可以变化。
node.js中的本机承诺确实具有特定的实现。就我个人而言,我不知道为什么您应该编写依赖于此特定实现的代码,但是很多人似乎很好奇,因此我将进行解释。
您可以在本文中看到一个很好的图:Promises, nextTicks and setImmediates。本机承诺是使用微任务队列来实现的。本质上,它是另一个队列,如nextTick队列,该队列在nextTickQueue
之后但在其他任何队列之前进行处理。因此,排队的.then()
或.catch()
处理程序在已调度的nextTick
调用之后和之后且在任何其他类型的事件(计时器,I / O完成等)之前立即运行。
非本机Promise实现(例如Bluebird或Q)无法创建在nextTick队列之后处理的新microTasks队列,因此它们使用setImmediate()
或process.nextTick()
。
关于javascript - 我应该如何在JavaScript中“屈服”?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53337067/
我对现代JavaScript(ES8)有点陌生。异步产生的首选方法是什么,即使用await在事件循环的某些将来迭代中继续执行脚本?我看到了以下选项: async function yield1() {
我有一个 Duck 类,它有一个生成 block 的 initialize 方法: class Duck def initialize() if block_given? yi
我目前正在学习 F#,我非常喜欢 yield! (yield-bang) 运算符。不仅因为它的名字,当然也因为它的作用。 yield! 运算符基本上允许您从序列表达式中产生序列的所有元素。这对于组合枚
我是一名优秀的程序员,十分优秀!