栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

构造函数中的异步操作

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

构造函数中的异步操作

将异步操作放入构造函数中特别困难。这有几个原因:

  1. 构造函数需要返回新创建的对象,因此它不能返回将告诉您异步操作何时完成的承诺。
  2. 如果在构造函数内进行异步操作以设置一些实例数据,并且构造函数返回对象,则调用代码将无法知道异步操作何时真正完成。

由于这些原因,您通常不希望在构造函数中执行异步操作。IMO,下面最干净的体系结构是工厂函数,它返回一个可解析为最终对象的承诺。您可以在工厂函数中执行任意数量的异步工作(调用对象上的任何方法),并且直到对象完全形成后,才将其公开给调用方。

这些是处理该问题的各种选项中的一些:

使用返回承诺的工厂函数

这使用了工厂功能,可以为您完成一些更常见的工作。在完全初始化之前,它也不会显示新对象,这是一个很好的编程习惯,因为调用者不会偶然尝试使用尚未完成异步处理的部分形成的对象。factory函数选项还通过拒绝返回的promise干净地传播错误(同步或异步):

// don't make this class definition public so the constructor is not publicclass MyObj() {   constructor(somevalue) {       this.someProp = somevalue;   }   init() {       return Service.getService().then(val => {          this.asyncProp = val;          return this;       });   }}function createMyObj(somevalue) {    let x = new MyObj(someval);    return x.init();}createMyObj(someval).then(obj => {    // obj ready to use and fully initialized here}).catch(err => {    // handle error here});

如果使用模块,则只能导出工厂函数(无需导出类本身),从而强制执行对象正确初始化,并且在完成初始化之前不使用该对象。

将异步对象初始化分为可以返回承诺的单独方法

class MyObj() {   constructor(somevalue) {       this.someProp = somevalue;   }   init() {       return Service.getService().then(val => {          this.asyncProp = val;       });   }}let x = new MyObj(someval);x.init().then(() => {    // ready to use x here}).catch(err => {    // handle error});

使用事件表示完成

许多与I / O相关的API中都使用了该方案。通常的想法是,您从构造函数中返回一个对象,但是调用者知道该对象直到发生特定事件才真正完成其初始化。

// object inherits from EventEmitterclass MyObj extends EventEmitter () {   constructor(somevalue) {       this.someProp = somevalue;       Service.getService().then(val => {          this.asyncProp = val;          // signal to caller that object has finished initializing          this.emit('init', val);       });   }}let x = new MyObj(someval);x.on('init', () => {    // object is fully initialized now}).on('error', () => {    // some error occurred});

将异步操作放入构造函数的骇人方式

尽管我不建议您使用此技术,但这是将异步操作放入实际构造函数本身的过程:

class MyObj() {   constructor(somevalue) {       this.someProp = somevalue;       this.initPromise = Service.getService().then(val => {          this.asyncProp = val;       });   }}let x = new MyObj(someval);x.initPromise.then(() => {   // object ready to use now}).catch(err => {   // error here});

注意,您会在各种API的许多地方看到第一个设计模式。例如,对于node.js中的套接字连接,您将看到以下内容:

let socket = new net.Socket(...);socket.connect(port, host, listenerCallback);

套接字是在第一步中创建的,但随后在第二步中已连接到某些对象。而且,同一个库具有工厂功能

net.createConnection()
,该功能将这两个步骤组合为一个功能(上述第二个设计模式的说明)。该
net
模块实例并不碰巧使用诺言(很少有原创的NodeJS的API做),但它们完成使用回调和事件相同的逻辑。


有关代码的其他说明

this
的代码中的值可能也有问题。一个
.then()
处理程序不自然保护的价值
this
从周围环境中如果你传递一个普通
function(){}
的参考。因此,在此:

function Constructor(){   Service.getService().then(function(data){      this.arr = data.data.array;      return this.arr   })}

this
当您尝试做时的值将
this.arr = data.data.array;
是不正确的。解决ES6中该问题的最简单方法是改为使用粗箭头功能:

function Constructor(){   Service.getService().then(data => {      this.arr = data.data.array;      return this.arr   });}


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/400586.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号