构造函数中的异步操作 [英] Asynchronous operations in constructor

查看:167
本文介绍了构造函数中的异步操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Hey I have question about prototype and inheretience in functions. Could you explan me how I can return arr from constructor and add this arr to prototype?

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();

getArray中,this.arr是未定义的. Service and getService()是角度工厂以及前端和后端之间的连接

And in getArray this.arr is undefined. Service and getService() are angular factory and connection between front and back-end

推荐答案

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

It is particularly difficult to put asynchronous operations in a constructor. This is for several reasons:

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

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

For these reasons, you usually don't want to do an async operation inside a constructor. IMO, the cleanest architecture below is the factory function that returns a promise that resolves to your finished object. You can do as much asynchronous stuff as you want in the factory function (call any methods on the object) and you don't expose the object to the caller until it is fully formed.

以下是用于处理该问题的各种选项:

These are some of the various options for dealing with that issue:

使用返回承诺的工厂函数

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

This uses a factory function that does some of the more common work for you. It also doesn't reveal the new object until its fully initialized which is a good programming practice as the caller can't accidentally try to use a partially formed object in which the asynchronous stuff hasn't finished yet. The factory function option also cleanly propagates errors (either synchronous or asynchronous) by rejecting the returned 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
});

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

If you're using modules, you can export only the factory function (no need to export the class itself) and thus enforce that the object is initialized properly and not used until that initialization is done.

将异步对象初始化中断到一个单独的方法中,该方法可以返回promise

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中使用.一般的想法是,您从构造函数中返回一个对象,但调用者知道该对象直到发生特定事件才真正完成其初始化.

This scheme is used in a lot of I/O related APIs. The general idea is that you return an object from the constructor, but the caller knows that object hasn't really completed its initialization until a particular event occurs.

// 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
});

将异步操作放入构造函数的荒谬方式

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

Though I wouldn't recommend using this technique, this is what it would take to put the async operation in the actual constructor itself:

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中的套接字连接,您将看到以下内容:


Note, you see the first design pattern in many places in various APIs. For example, for a socket connection in node.js, you would see this:

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

套接字是在第一步中创建的,但随后在第二步中已连接到某些对象.然后,同一个库具有工厂功能net.createConnection(),该功能将这两个步骤组合为一个功能(上述第二种设计模式的说明). net模块示例不会碰巧使用promise(很少有nodejs原始api会使用promise),但是它们使用回调和事件来实现相同的逻辑.

The socket is created in the first step, but then connected to something in the second step. And, then the same library has a factory function net.createConnection() which combines those two steps into one function (an illustration of the second design pattern above). The net module examples don't happen to use promises (very few nodejs original apis do), but they accomplish the same logic using callbacks and events.

关于代码的其他说明

您的代码中的this值也可能有问题.如果将常规的function() {}引用传递给.then()处理程序,自然不会从周围环境中保留this的值.因此,在此:

You likely also have an issue with the value of this in your code. A .then() handler does not naturally preserve the value of this from the surrounding environment if you pass it a regular function() {} reference. So, in this:

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

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

The value of this when you try to do this.arr = data.data.array; is not going to be correct. The simplest way to fix that issue in ES6 is to use a fat arrow function instead:

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

这篇关于构造函数中的异步操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆