简体   繁体   English

如何创建包含异步调用的 Javascript (es5) 构造函数 function

[英]How to create a Javascript (es5) constructor function containing an asynchronous call

I'm trying to create a constructor function that includes a call to indexedDB or localStorage to retrieve some data if it exists and then populate it's values, either from the cache or the given (default) data.我正在尝试创建一个构造函数 function ,其中包括对 indexedDB 或 localStorage 的调用,以检索一些数据(如果存在),然后从缓存或给定(默认)数据中填充它的值。

I had it working, but somehow broke my code.我让它工作,但不知何故破坏了我的代码。 Given that my method of programming is "hit it with a stick until it works", the code is an absolute mess.鉴于我的编程方法是“用棍子敲打直到它起作用”,代码绝对是一团糟。 So I have simplified the problem down to a contrived example, which fails in the same way.所以我将问题简化为一个人为的例子,它以同样的方式失败。

Removing the async function (setTimeout) fixes the problem, but then my code won't work.删除异步 function (setTimeout) 可以解决问题,但是我的代码将无法正常工作。

var person = (function(){
    function privateFn (value){
        return value;
    }
    function private_asyncFn(value, callback){
        setTimeout(function () {
            return callback(value);
        }, 10);
    }
    var DATA, NUM;
    var personConstructor = function(name, age, gender, callback){
        this.name = privateFn(name);
        this.gender = privateFn(gender);
        DATA = DATA || [];
        NUM = NUM || 0;
        this.num = NUM;
        private_asyncFn(age, function(ret){
            DATA[NUM++] = { name: this.name, age: ret };
            if (callback instanceof Function) return callback(this.name);
        }.bind(this));
    };
    personConstructor.prototype.getAge = function () {
        if (this.gender === "male") return DATA[this.num].age;
        else return DATA[this.num].age < 20 ? 18 : (Math.floor(DATA[this.num].age / 10) - 1) + "9 and holding";
    };
    return personConstructor;
})();

var name1;
var person1 = new person("jill", 32, "female", function(name){
    name1 = name;
});
var age1 = person1.getAge(); //Uncaught TypeError: Cannot read property 'age' of undefined????

I see other code on SO using classes and promises and async/await, but I don't understand how that all works, so this code is a bit "old school", sorry about that.我在 SO 上看到了使用类和承诺以及异步/等待的其他代码,但我不明白这一切是如何工作的,所以这段代码有点“老派”,对此感到抱歉。

In this example, can you retrieve the age of the person, immediately following the initialization of a new person?在这个例子中,你能在新人初始化之后立即检索人的年龄吗?

There is no way to make an asynchronous constructor.没有办法制作异步构造函数。 What you want to do instead is probably create an asynchronous function that will yield your constructed object after the asynchronous operation is completed.您想要做的可能是创建一个异步 function ,它将在异步操作完成后生成您构造的 object 。 I'd give you a more concrete example, but frankly, I don't understand what the async part of your code is attempting to do.我会给你一个更具体的例子,但坦率地说,我不明白你的代码的异步部分试图做什么。 Here's an example of how you might accomplish this, though:不过,这是一个如何完成此操作的示例:

function Person(name, age, gender) {
  this.name = name
  this.gender = gender
  this.age = age
}

Person.prototype.getAge = function() {
  return this.age
}

Person.create = function create(name, age, gender, done) {
  var person = new Person(name, age, gender)
  setTimeout(function () {
    done(null, person)
  }, 1000)
}

Person.create("jill", 32, "female", function (person) {
  person.getAge()
})

I would recommend using Promises and ES6 classes if you don't need to support very old browsers.如果您不需要支持非常旧的浏览器,我建议您使用 Promises 和 ES6 类。

class Person {
  static create(name, age, gender) {
    return new Promise(resolve => {
      const person = new Person(name, age, gender)
      resolve(person)
    })
  }

  constructor(name, age, gender) {
    this.name = name
    this.age = age
    this.gender = gender
  }

  getAge() {
    return this.age
  }
}

Person.create("jill", 32, "female")
  .then((person) => {
    person.getAge()
  })

It would be helpful when you post your next SO question to give a real world example of what your code is trying to achieve - getAge returning different results depending on gender doesn't make much sense:)当您发布下一个 SO 问题以给出您的代码试图实现的目标的真实示例时,这将很有帮助 - getAge根据性别返回不同的结果没有多大意义:)

By moving all of the async logic into an init function that is called after creating a new person keeps the constructor synchronous.通过将所有异步逻辑移动到在创建new person后调用的init function 中,可以使构造函数保持同步。 Then getAge can be called from inside the init callback function using either this.getAge() or person1.getAge() (because person1 exists now)然后可以使用getAge this.getAge()person1.getAge()init回调 function 内部调用 getAge(因为 person1 现在存在)

var person = (function(){

    function privateFn (value){
        return value;
    }

    function private_asyncFn(value, callback){
        setTimeout(function () {
            return callback(value);
        }, 10);
    }

    var DATA, NUM;

    //removed all data inputs and callback from constructor function
    var personConstructor = function(){

        //initialise publically accessible data    
        this.name = null;
        this.gender = null;

        //initialise blank data store
        DATA = DATA || [];
        NUM = NUM || 0;
        this.num = NUM;
        DATA[NUM++] = { 
            age: null
        };
    };

    //created new init function
    personConstructor.prototype.init = function (name, age, gender, callback){

        this.name = privateFn(name);
        this.gender = privateFn(gender);

        private_asyncFn(age, function(ret){

            DATA[this.num].age = ret;

            //note: .call(this,...) on the callback to use "this" in the callback
            if (callback instanceof Function) return callback.call(this, this.name);

        }.bind(this));
    };

    personConstructor.prototype.getAge = function () {
        if (this.gender === "male") return DATA[this.num].age;
        else return DATA[this.num].age < 20 ? 18 : (Math.floor(DATA[this.num].age / 10) - 1) + "9 and holding";
    };

    return personConstructor;
})();

var name1, age1;
var person1 = new person();
person1.init("jill", 32, "female", function(name){
    name1 = name;
    age1 = this.getAge();
    console.log(age1);//29 and holding, YES!
});

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

相关问题 如何使构造函数指向ES5中的超级函数原型 - How to make Constructor function to point to Super function prototype in ES5 在Javascript ES5和ES6中,如何严格影响此关键字在Function对象的调用和应用方法的上下文中 - How does use strict impact this keyword in the context of call and apply method of a Function object in Javascript ES5 and ES6 如何存根ES5类构造函数? - How to stub ES5 class constructor? 如何使用ES5 Object.create和对象文字语法模拟构造函数? - How to emulate a constructor with ES5 Object.create and object literal syntax? 将 ES6 箭头函数转换为 ES5 函数 JavaScript - Convert ES6 arrow function to ES5 function JavaScript 如何调用异步 JavaScript function? - How to call an asynchronous JavaScript function? 使用带有 Getter/Setter 的构造函数初始化 JavaScript/ES5 对象 - Initialization of a JavaScript/ES5 object using a constructor with Getter/Setter 如何在调用异步函数之后的javascript / jquery代码中创建暂停 - How to create a pause in javascript/jquery code that follows a call to asynchronous function 如何避免在JavaScript(ES5 / ES6)中使用&#39;this&#39;指针? - How to avoid using 'this' pointer in javascript (ES5/ES6)? 我如何在 ES5 中的递归匿名函数上应用 TCO(尾调用优化) - How do i apply TCO(Tail Call Optimiztion) on recursive anonymous Function in ES5
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM