2016-05-31 52 views
31

作爲一種組織模式,ES6 Classes可以提供什麼樣的異步代碼。下面是ES7 async/await的一個例子,ES6類可以有一個異步方法,或ES7中的構造方法嗎?JavaScript ES6類與異步代碼庫的任何用法?

我可以這樣做:

class Foo { 
    async constructor() { 
     let res = await getHTML(); 
     this.res = res 
    } 
} 

,如果沒有應該如何構造的工作,做到這一點?

class Foo { 
    constructor() { 
     getHTML().then(function (res) { 
      this.res = res 
     } 
    } 
} 

如果沒有這些模式的工作,可以在ES6構造(而且班)class支持任何形式的異步的,關於對象的狀態下工作?或者,它們只是用於純粹的同步代碼庫嗎?以上的例子是在構造函數中,但他們並不需要是..推下來的問題多了一個層次..

class Foo { 
    myMethod() { 
     /* Can I do anything async here */ 
    } 
} 

或者,吸氣劑...

class Foo { 
    get myProp() { 
     /* Is there any case that this is usefully asynchronous */ 
    } 
} 

的只有我能想到的例子是在同一個方法/構造函數/ getter中並行運行一些東西,但要在結束之前解決整個問題。我只是感到困惑,因爲它似乎與所有的推動完全異步庫,這只是用來混淆事物。除了教科書的例子,我找不到一個他們有用的應用程序。

+0

您可以從構造函數返回一個承諾,該實例通過該實例解析,因此您可以在實例初始化後訪問該實例。 –

+0

@KevinB這個想法確實發生在我身上,但這聽起來很可怕。 –

+0

我也不特別喜歡它,但是......還有什麼其他方式?必須有一個回調的地方,它要麼是一個承諾,要麼是作爲參數傳遞的回調。異步/等待仍然有一個回調,你只是沒有看到它。 –

回答

27

我可以做async constructor()

不,那是一個語法錯誤 - 就像constructor*()。構造函數是一種不返回任何東西的方法(沒有承諾,沒有生成器),它只是初始化實例。

,如果不應該怎麼做這個

這樣的一個構造的工作應該不存在的,看到Is it bad practice to have a constructor function return a Promise?

能ES6類支持任何形式的不同步是對對象的狀態進行操作?或者,它們只是用於純粹的同步代碼庫嗎?

是的,您可以在類上使用異步方法(即使對於建議的async語法),並且getter也可以返回promise。

但是,您需要決定在某個異步過程仍處於活動狀態時調用方法時應該發生什麼情況。如果你想讓它對所有的操作進行排序,你應該將實例的狀態存儲在一個承諾中,以便可以鏈接到該序列的末尾。或者,如果您想允許並行操作,最好的方法是讓您的實例不可變並返回另一個實例的承諾。

+2

這是一個非常好的答案,我可以編輯它以提供通過承諾鏈接到自身的類的示例。我仍然不滿意這是一個好主意。它看起來更像是一種反模式。 –

+5

@EvanCarroll:這是一個好主意取決於你在做什麼。 ES6'class'語法不會在表上引入任何新東西,對象(實例)中的異步和狀態總是很複雜。 – Bergi

3

Classes可用於排列異步任務的另一種方式是獨家使用static methods

class Organizer { 
    static async foo() { 
     const data = await this.bar(); 
     data.key = value; 
     return data; 
    } 
    static async bar() { 
     return {foo:1, bar:2} 
    } 
}; 

Organizer.foo(); 

當然,這只不過是創建一個簡單的對象文本,或一個新的文件,幷包括它不同,除了可以更清潔extend它。

+5

你永遠不應該那樣做。只需使用一個對象字面值(你可以使用Object.create和Object.assign來擴展它們)。或者,給定ES6模塊,只需使用多個命名導出 - 擴展它們就更容易了,就像寄生繼承一樣。 – Bergi

4

ECMAScript 2017旨在成爲異步方法的類。

調用另一個異步或承諾返回函數是一個單行!

的極具表現力的代碼,而無需中斷頂部讀取到下無論延遲執行的

如果有回調,替代錯誤處理,並行執行或其他未滿足的需求,在實例函數體承諾。最好在函數體中而不是在承諾執行程序中使用代碼,並且請注意,沒有try-catch包裝回調代碼:在那裏做無所事事。

異步方法可以返回一個承諾,一個普通值,或者拋出

導入Node.js用來愛的人回調的API,我們現在會恨與激情:他們必須全部承諾

包裹

異步的美容/等待是錯誤冒泡隱含

class MyClass { 
    async doEverything() { 
    const sumOfItAll = await http.scrapeTheInternet() + 
     await new Promise((resolve, reject) => 
     http.asyncCallback((e, result) => !e ? resolve(result) : reject(e))) 
    return this.resp = sumOfItAll 
    } 
} 

如果僅限於2015年的ECMAScript和沒有異步,返回承諾值:

class ES2015 { 
    fetch(url) { 
    return new Promise((resolve, reject) => 
     http.get(url, resolve).on('error', reject)) 
     .then(resp => this.resp = resp) // plain ECMAScript stores result 
     .catch(e => { // optional internal error handler 
     console.error(e.message) 
     throw e // if errors should propagate 
     }) 
    } 
} 

這個ECMAScript 2015版本就是你真正想問的問題,任何期望的行爲都可以使用返回的promise結構進行編碼。

如果你確實想要在構造函數中執行promise,那麼傳入then-catch函數或提供一些回調構造是個好主意,這樣消費者就可以對promise的實現或拒絕採取行動。在構造函數中,在實際工作之前等待nextTick /。

每一個承諾需要一個最終趕上或會有麻煩

0

這是一個遲到的反應,但你的第二個例子不工作的原因是因爲上下文錯誤的。當您通過function() {}作爲參數Promise.prototype.then()時,函數內部的詞彙this將是函數本身,而不是類。這就是爲什麼設置this.res似乎什麼也不做:this,在這種情況下,指的是函數自己的範圍。

有訪問在Javascript中,經典的一個(您在ES5代碼中看到大量存在),外部範圍的幾種方法:

class Foo { 
    constructor() { 
    var _this = this 

    getHTML().then(function (res) { 
     _this.res = res 
    }) 
    } 
} 

通過向類this一個參考,你可以訪問它在內部範圍內。

ES6的做法是使用arrow functions,它不會創建新的範圍,而是「保留」當前範圍。

class Foo { 
    constructor() { 
    getHTML().then(res => this.res = res) 
    } 
} 
從上下文關注

除此之外,這仍然不是在我看來,一個最佳的異步模式,因爲你有沒有辦法當getHTML()已經完成,或者更糟的是,未能就知道了。用async functions可以很好地解決這個問題。雖然你不能創建一個async constructor() { ... },你可以在構造函數中發起一個承諾,並且在依賴它的函數中發起承諾await

Example gist在類構造函數中的異步屬性。