简体   繁体   English

为什么将代码放入setTimeout中可以使Angular正常工作?

[英]Why does putting code inside a setTimeout make Angular work properly?

I've been trying to create a simple directive in Angular 5 but hit walls. 我一直在尝试在Angular 5中创建一个简单的指令,但遇到了麻烦。 I recently discovered that adding my code inside a setTimeout function makes it work as I expect. 我最近发现,将我的代码添加到setTimeout函数中可以使其按预期工作。 In this case I expect the form to appear populated with " yolo " 在这种情况下,我希望表单显示为“ yolo

I don't completely understand why. 我不完全明白为什么。 I understand that it has to do with the way Angular bootstraps but I don't understand why it is that way - and especially why code in the constructor is discarded (After all, then what's the point of the constructor?) 我知道这与Angular Bootstraps的方式有关,但我不明白为什么会这样-尤其是为什么丢弃构造函数中的代码(毕竟,构造函数的意义是什么?)

Please find a simplified copy of the code in question below: 请在下面找到相关代码的简化副本:

With setTimeout 使用setTimeout

Without setTimeout 没有setTimeout

@Directive({
  selector: '[formControlName][phone]',
  host: {
    '(ngModelChange)': 'onInputChange($event)'
  }
})
export class PhoneMask {

  constructor(public model: NgControl) {
    // with setTimeout
    setTimeout(() => {  
      this.model.valueAccessor.writeValue('yolo');
    });

    // without setTimeout
    // this.model.valueAccessor.writeValue('yolo');

  }

}

@Component({
  selector: 'my-app',
  providers: [],
  template: `
  <form [formGroup]="form">
    <input type="text" phone formControlName="phone"> 
  </form>
  `,
  directives: [PhoneMask]
})
export class App {
  constructor(fb:FormBuilder) {
    this.form=fb.group({
      phone:['']
    })
  }
}

@NgModule({
  imports: [ BrowserModule, FormsModule, ReactiveFormsModule ],
  declarations: [ App, PhoneMask ],
  bootstrap: [ App ]
})
export class AppModule {}

When you put code in a setTimeout you are effectively taking it out of the current call stack, once the whole call stack is executed the event loop will pick your code and put it on top of a new call stack and the execution will start. 当将代码放入setTimeout中时,实际上是将其从当前调用堆栈中删除,一旦执行了整个调用堆栈,事件循环就会选择您的代码并将其放在新的调用堆栈之上,然后开始执行。 You may come around the term tick, well thats a tick, when the call stack is done. 调用堆栈完成后,您可能会碰到术语“滴答”,也就是“滴答”。 In your case, setTimeout is basically 0ms but the code is removed from the current stack, so everything else completes, then your code runs, modifies the property and angular change detector detects the change. 在您的情况下,setTimeout基本上为0ms,但是代码已从当前堆栈中删除,因此其他所有操作都将完成,然后您的代码运行,修改属性并由角度变化检测器检测到变化。

At the time of constructing your directive, Angular doesn't check for changes in the directive's (or rather its host component's) properties. 在构造指令时,Angular不会检查指令(或它的宿主组件)属性中的更改。 While moving the relevant code to setTimeout works, it's much better (ie. not a hacky workaround) to do such things in eg. 在将相关代码移至setTimeout ,例如在进行此类操作时要好得多(即,不是一个棘手的解决方法)。 ngOnInit : ngOnInit

// PhoneMask implements OnInit
ngOnInit() {
  this.model.valueAccessor.writeValue('yolo')
}

Worth reading: https://stackoverflow.com/a/35763811/7178441 值得一读: https : //stackoverflow.com/a/35763811/7178441


Update: @csmckelvey explained in comments why the setTimeout trick actually works: 更新:@csmckelvey在注释中解释了setTimeout技巧实际上起作用的原因:

Because it causes the code to be delayed until after the constructor has been executed. 因为这会导致代码延迟到构造函数执行之后。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么setTimeout中的代码在JavaScript中不起作用? - Why does my code in setTimeout not work in JavaScript? 在 React 中,为什么 setTimeout 中的 setState 只能与 state 的副本一起正常工作? - In React, why does setState in a setTimeout only work properly with a copy of the state? setTimeout在Typescript / Angular中的forEach循环内不起作用 - setTimeout does not work inside forEach loop in Typescript / Angular setTimeout 在事件侦听器中不起作用 - setTimeout does not work inside eventlistener 为什么setTimeout无法按预期工作? - Why setTimeout does not work as expected? 为什么setTimeout在递归函数内的循环VS中无法正确执行 - Why does setTimeout not execute properly inside a loop VS inside a recursive function 为什么 Angular 服务在 setTimeout 和 setInterval 中不工作? - why Angular services are not working inside the setTimeout and setInterval? setInterval 中的 setTimeout 不能正常工作 - setTimeout inside setInterval does not work well 触发器&#39;touchstart&#39;在setTimeout内部不起作用 - Trigger 'touchstart' does not work inside of setTimeout 为什么 setTimeout 中的 promise 在随后的 setTimeout function 之前解决? - Why does a promise inside setTimeout resolve before a subsequent setTimeout function?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM