当前位置: 首页 > 面试题库 >

构造函数中的异步操作

郦祯
2023-03-14
问题内容

嘿,我对函数的原型和固有性有疑问。您能否解释一下如何从构造函数返回arr并将此arr添加到原型中?

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

Constructor.prototype.getArray = function(){
   console.log(this.arr)
})
example.getArray();

并且在getArraythis.arr中是未定义的。Service and getService()有角度的工厂以及前端和后端之间的连接


问题答案:

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

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

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

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

使用返回承诺的工厂函数

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

// don't make this class definition public so the constructor is not public
class 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 EventEmitter
class 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
   });
}


 类似资料:
  • 问题内容: 我如何最好地处理以下情况? 我有一个构造函数,需要一些时间才能完成。 我看到了三个选项,每个选项似乎都与众不同。 一种 ,向构造函数添加回调。 第二 ,使用EventEmitter发出“已加载”事件。 或三 ,阻止构造函数。 但我以前从未见过任何完成的事情。 我还有什么其他选择? 问题答案: 鉴于有必要避免在Node中进行阻塞,事件或回调的使用并不奇怪(1)。 稍加修改为2,即可将其与

  • 问题内容: 目前,我正在尝试在类构造函数中使用。这样一来,我就可以为正在从事的Electron项目获取自定义标签。 但是,目前该项目无法正常工作,并出现以下错误: 有没有办法避免这种情况,以便我可以在其中使用异步/等待?而不需要回调或.then()? 问题答案: 这 永远 行不通。 该关键字允许在标记为函数中使用,但它也是功能转换成一个承诺发生器。因此,标有的函数将返回承诺。另一方面,构造函数返回

  • 问题内容: 在C ++中,对象的生命周期从构造函数成功完成时开始。在构造函数内部,该对象尚不存在。 问:从构造函数发出异常是什么意思? 答:这意味着构造已失败,该物体从未存在,其寿命从未开始。[ 来源 ] 我的问题是:Java是否同样适用?例如,如果我移交给另一个对象,然后构造函数失败,会发生什么情况? 这个定义明确吗?现在是否有对非对象的引用? 问题答案: 该对象存在,但未正确初始化。 每当构造

  • 问题内容: 某个地方的人告诉我Java构造函数是同步的,因此在构造过程中不能同时访问它,而我在想:是否有构造函数将对象存储在映射中,而另一个线程在构造之前从该映射检索它完成后,该线程是否会阻塞,直到构造函数完成? 让我用一些代码演示: 假设put / get是地图上唯一的操作,因此我不会通过迭代之类的方法来获取CME,并尝试在此忽略其他明显的缺陷。 我想知道的是,如果另一个线程(显然不是构造该对象

  • 你好,我正在使用异步/等待在我的打字稿项目,但我得到这个日志: [ts]ES5/ES3中的异步函数或方法需要Promise构造函数。确保您有一个Promise构造函数的声明,或者在您的选项中包含ES2015。 我该如何解决这个问题?

  • 异步编程对JavaScript语言太重要。Javascript语言的执行环境是“单线程”的,如果没有异步编程,根本没法用,非卡死不可。 ES6诞生以前,异步编程的方法,大概有下面四种。 回调函数 事件监听 发布/订阅 Promise 对象 ES6将JavaScript异步编程带入了一个全新的阶段,ES7的Async函数更是提出了异步编程的终极解决方案。 基本概念 异步 所谓"异步",简单说就是一个