dcs*_*san 58 constructor async-await typescript
我在构造函数中有一些我想要的设置,但似乎是不允许的
这意味着我不能使用:
我该怎么做呢?
目前我有类似的东西,但这不保证按我想要的顺序运行?
async function run() {
let topic;
debug("new TopicsModel");
try {
topic = new TopicsModel();
} catch (err) {
debug("err", err);
}
await topic.setup();
Run Code Online (Sandbox Code Playgroud)
Ami*_*mid 33
构造函数必须返回它'构造'的类的实例,因此不可能返回Promise <...>并等待它.
您可以:
每当您想要"完成"对象构造时,请调用它
async function run()
{
let topic;
debug("new TopicsModel");
try
{
topic = new TopicsModel();
await topic.setup();
}
catch (err)
{
debug("err", err);
}
}
Run Code Online (Sandbox Code Playgroud)Pet*_*one 18
如果您不能将对象放在promise中,请在对象中放置promise.
将构造完成承诺公开为构造对象的属性.当构造的异步部分完成时,它应解决承诺.
无论是Promise在promise解决之前还是之后执行都无关紧要.promise规范声明调用Task已经解析的promise会立即执行处理程序.
class Foo {
public Ready: Promise.IThenable<any>;
constructor() {
...
this.Ready = new Promise((resolve, reject) => {
$.ajax(...).then(result => {
// use result
resolve(undefined);
}).fail(reject);
});
}
}
var foo = new Foo();
foo.Ready.then(() => {
//do stuff that needs foo to be ready, eg apply bindings
});
Run Code Online (Sandbox Code Playgroud)
为什么.then(...)而不是then?因为ES6.根据需要调整以适合您的目标.
在评论中,有人建议我应该将此解决方案框起来,resolve(undefined);以便更直接地解决所提出的问题.
这是一个糟糕的解决方案,因为它只允许紧跟在await语句之后的作用域中的代码在完成时等待.将promise对象公开为异步初始化对象的属性意味着任何地方的任何代码都可以保证初始化完成,因为promise在范围内的任何地方都在范围内,因此保证在风险存在的任何地方都可用.
此外,使用await关键字不太可能是任何非大学作业的项目的可交付成果,证明使用了await关键字.
这是我的原创作品.我设计了这种设计模式,因为我对外部工厂和其他类似的解决方法不满意.虽然搜索了一段时间,我发现我的解决方案没有现有技术,所以我声称自己是这种模式的创始人,直到有争议.
在一条评论中,@ suhas建议使用resolve();而不是await,这将起作用,但它的广泛兼容性较差.关于兼容性问题,自我写这篇文章以来,Typescript已经发生了变化,现在你必须声明await
Had*_*ady 12
使用私有构造函数和静态工厂方法 FTW。这是强制执行任何验证逻辑或数据丰富、远离客户端封装的最佳方式。
class Topic {
public static async create(id: string): Promise<Topic> {
const topic = new Topic(id);
await topic.populate();
return topic;
}
private constructor(private id: string) {
// ...
}
private async populate(): Promise<void> {
// Do something async. Access `this.id` and any other instance fields
}
}
// To instantiate a Topic
const topic = await Topic.create('1234');
Run Code Online (Sandbox Code Playgroud)
小智 9
我找到了一个看起来像的解决方案
export class SomeClass {
private initialization;
// Implement async constructor
constructor() {
this.initialization = this.init();
}
async init() {
await someAsyncCall();
}
async fooMethod() {
await this.initialization();
// ...some other stuff
}
async barMethod() {
await this.initialization();
// ...some other stuff
}
Run Code Online (Sandbox Code Playgroud)
它之所以有效,是因为支持 async/await 的 Promise 可以使用相同的值多次解析。
我知道它安静的旧,但另一个选择是有一个工厂,它将创建对象并等待其初始化:
// Declare the class
class A {
// Declare class constructor
constructor() {
// We didn't finish the async job yet
this.initialized = false;
// Simulates async job, it takes 5 seconds to have it done
setTimeout(() => {
this.initialized = true;
}, 5000);
}
// do something usefull here - thats a normal method
usefull() {
// but only if initialization was OK
if (this.initialized) {
console.log("I am doing something usefull here")
// otherwise throw error which will be catched by the promise catch
} else {
throw new Error("I am not initialized!");
}
}
}
// factory for common, extensible class - thats the reason of the constructor parameter
// it can be more sophisticated and accept also params for constructor and pass them there
// also, the timeout is just example, it will wait about 10s (1000 x 10ms iterations
function factory(construct) {
// create a promise
var aPromise = new Promise(
function(resolve, reject) {
// construct the object here
var a = new construct();
// setup simple timeout
var timeout = 1000;
// called in 10ms intervals to check if the object is initialized
function waiter() {
if (a.initialized) {
// if initialized, resolve the promise
resolve(a);
} else {
// check for timeout - do another iteration after 10ms or throw exception
if (timeout > 0) {
timeout--;
setTimeout(waiter, 10);
} else {
throw new Error("Timeout!");
}
}
}
// call the waiter, it will return almost immediately
waiter();
}
);
// return promise of object being created and initialized
return aPromise;
}
// this is some async function to create object of A class and do something with it
async function createObjectAndDoSomethingUsefull() {
// try/catch to capture exceptions during async execution
try {
// create object and wait until its initialized (promise resolved)
var a = await factory(A);
// then do something usefull
a.usefull();
} catch(e) {
// if class instantiation failed from whatever reason, timeout occured or usefull was called before the object finished its initialization
console.error(e);
}
}
// now, perform the action we want
createObjectAndDoSomethingUsefull();
// spagetti code is done here, but async probably still runs
Run Code Online (Sandbox Code Playgroud)
请改用异步工厂方法。
class MyClass {
private mMember: Something;
constructor() {
this.mMember = await SomeFunctionAsync(); // error
}
}
Run Code Online (Sandbox Code Playgroud)
成为:
class MyClass {
private mMember: Something;
// make private if possible; I can't in TS 1.8
constructor() {
}
public static CreateAsync = async () => {
const me = new MyClass();
me.mMember = await SomeFunctionAsync();
return me;
};
}
Run Code Online (Sandbox Code Playgroud)
这将意味着您将不得不等待构建此类对象,但这已经隐含着这样一个事实,即您处在无论如何都必须等待某种构造它们的情况下。
您可以做另一件事,但我怀疑这不是一个好主意:
// probably BAD
class MyClass {
private mMember: Something;
constructor() {
this.LoadAsync();
}
private LoadAsync = async () => {
this.mMember = await SomeFunctionAsync();
};
}
Run Code Online (Sandbox Code Playgroud)
这可以工作,以前我从没有遇到过实际问题,但是这对我来说似乎很危险,因为当您开始使用它时,实际上不会完全初始化您的对象。
使用工厂。这是这些情况的最佳实践。
问题是为工厂模式定义 Typescript 类型很棘手,尤其是继承。
让我们看看如何在 Typescript 中正确实现它。
如果不需要类继承,模式是这样的:
class Person {
constructor(public name: string) {}
static async Create(name: string): Promise<Person> {
const instance = new Person(name);
/** Your async code here! **/
return instance;
}
}
const person = await Person.Create('John');
Run Code Online (Sandbox Code Playgroud)
如果你需要延长课程,你就会遇到问题。该Create方法始终返回基类。
在 Typescript 中,您可以使用泛型类来修复此问题。
type PersonConstructor<T = {}> = new (...args: any[]) => T;
class Person {
constructor(public name: string) {}
static async Create<T extends Person>(
this: PersonConstructor<T>,
name: string,
...args: any[]
): Promise<T> {
const instance = new this(name, ...args);
/** Your async code here! **/
return instance;
}
}
Run Code Online (Sandbox Code Playgroud)
class MyPerson extends Person {
constructor(name: string, public lastName: string) {
super(name);
}
}
const myPerson = await MyPerson.Create('John', 'Snow');
Run Code Online (Sandbox Code Playgroud)
您也可以扩展该Create方法。
class MyPerson extends Person {
constructor(name: string, public lastName: string) {
super(name);
}
static async Create<T extends Person>(
this: PersonConstructor<T>,
name: string,
lastName: string,
...args: any[]
): Promise<T> {
const instance = await super.Create(name, lastName, ...args);
/** Your async code here! **/
return instance as T;
}
}
const myPerson = await MyPerson.Create('John', 'Snow');
Run Code Online (Sandbox Code Playgroud)
我们可以通过利用非静态方法的异步代码来减少代码的冗长,在扩展方法时不需要通用类定义Create。
type PersonConstructor<T = {}> = new (...args: any[]) => T;
class Person {
constructor(public name: string) {}
protected async init(): Promise<void> {
/** Your async code here! **/
// this.name = await ...
}
static async Create<T extends Person>(
this: PersonConstructor<T>,
name: string,
...args: any[]
): Promise<T> {
const instance = new this(name, ...args);
await instance.init();
return instance;
}
}
Run Code Online (Sandbox Code Playgroud)
class MyPerson extends Person {
constructor(name: string, public lastName: string) {
super(name);
}
override async init(): Promise<void> {
await super.init();
/** Your async code here! **/
// this.lastName = await ...
}
}
const myPerson = await MyPerson.Create('John', 'Snow');
Run Code Online (Sandbox Code Playgroud)
是的,但有一个例外:工厂。
您可以这样做,但许多人会认为您的代码是一个不好的模式,因为构造函数:
Promise<Person>不是Person);| 归档时间: |
|
| 查看次数: |
36270 次 |
| 最近记录: |