2015-04-21 41 views
1

我使用io.js,一個已經支持ES6生成器而不需要特殊標記的節點分支,以及Kris Kowal的Q庫。在協程式JavaScript函數中避免「yield」重複

我在做的是一個遊戲腳本,其中幾乎每一個動作都是異步的,我使用Q.spawn來讓事情保持健全。這是我的代碼的當前狀態,它的工作原理如下:

var q = require('q'); 
var tw = require('./lib/typewriter'); 
q.spawn(function*() { 
    tw.clear(); 
    yield tw.type({d:100}, "August 3, 9:47 AM", {w:500}); 
    yield tw.type("District Court"); 
    yield tw.type("Defendant Lobby No. 2", {w:2000}); 
    yield tw.breakLine(); 
    yield tw.type({who:"Phoenix"}, {dh:true}, {d:30}, "(Boy am I nervous!)", {w:1500}); 
    yield tw.breakLine().then(function(){ throw new Error("BOOM!"); }); 
    yield tw.type({who:"Mia"}, {dh:true}, {d:40}, "Wright!", {w:1250}); 
    yield tw.type({di:true}, {d:50}, "Did you", {w:1000}, {d:0}, " ", {d:30}, "turn off the lights?", {w:1000}); 
    yield tw.type({di:true}, {d:400}, ". . .", {w:1000}); 
    yield tw.type({di:true}, {d:40}, "I can't see a thing!", {w:1000}); 
    yield tw.breakLine(); 
    process.exit(); 
}); 

但是,向每一行添加良率會很糟糕。我幾乎要向Luvit跳去這種瘋狂,但我給了JavaScript一個機會。

在正常情況下,我可以省略大部分收益,如:

var q = require('q'); 
var tw = require('./lib/typewriter'); 
q.spawn(function*() { 
    tw.clear(); 
    tw.type({d:100}, "August 3, 9:47 AM", {w:500}); 
    tw.type("District Court"); 
    tw.type("Defendant Lobby No. 2", {w:2000}); 
    tw.breakLine(); 
    tw.type({who:"Phoenix"}, {dh:true}, {d:30}, "(Boy am I nervous!)", {w:1500}); 
    tw.breakLine(); 
    tw.type({who:"Mia"}, {dh:true}, {d:40}, "Wright!", {w:1250}); 
    tw.type({di:true}, {d:50}, "Did you", {w:1000}, {d:0}, " ", {d:30}, "turn off the lights?", {w:1000}); 
    tw.type({di:true}, {d:400}, ". . .", {w:1000}); 
    tw.type({di:true}, {d:40}, "I can't see a thing!", {w:1000}); 
    yield tw.breakLine(); 
    process.exit(); 
}); 

只有一個收益率仍然存在,只是要確定process.exit()不會太早執行。打字機模塊實際上排隊了大多數命令,所以這是有效的。這是合理的。

然而,如果回調拋出的地方,如:

tw.breakLine().then(function(){ throw new Error("BOOM!"); }); 

則Q將它吞沒,並且因爲沒有catch處理器連接到這個承諾,它將是默默的垃圾收集。

如果JavaScript的發電機剛剛檢測表達式語句產生的承諾,並自動產生的是,這將是真棒(只要你可以選擇退出它在某種程度上,當然)。

是否有一個JavaScript預處理器可以做到這一點?

或者有沒有其他方法可以避免在每一行上明確地產生結果,但仍然可以捕獲異常?

+0

你爲什麼會有「*拋出某處*回調」呢?如果您使用回調,爲什麼不屈服?或者它本身就是失敗的? – Bergi

+0

許多事情都可能導致拋出異常,例如由於函數拋出TypeError而調用未定義屬性的錯誤。我只是不想讓這些事情基本上沒有報道,而且幾乎可以在任何地方發生。 –

+0

是的,但是如果bug存在於'tw'庫中,那麼基本上你會被警告,並且不能做太多事情。如果圖書館有內部排隊的話,圖書館有責任拒絕回覆的承諾,並承諾依賴它。 – Bergi

回答

0

如果JavaScript生成器剛剛檢測到產生promise的表達式語句並自動生成該語句,那就太棒了。

It would be terrible

或者是否有其他方法可以避免在每一行上明確地產生收益,但是仍然會捕獲異常?

不是真的。但是,對於您的使用情況下,我會推薦使用異步的輔助功能,以減少使用的yield S上的號碼:

var paragraph = q.async(function*(lines) { 
    for (let line of lines) 
     yield tw.type(...line); 
    yield tw.breakLine(); 
}); 
q.spawn(function*() { 
    tw.clear(); 
    yield paragraph([ 
     [{d:100}, "August 3, 9:47 AM", {w:500}], 
     ["District Court"], 
     ["Defendant Lobby No. 2", {w:2000}] 
    ]); 
    yield paragraph([ 
     [{who:"Phoenix"}, {dh:true}, {d:30}, "(Boy am I nervous!)", {w:1500}] 
    ]); 
    throw new Error("BOOM!"); 
    yield paragraph([ 
     [{who:"Mia"}, {dh:true}, {d:40}, "Wright!", {w:1250}], 
     [{di:true}, {d:50}, "Did you", {w:1000}, {d:0}, " ", {d:30}, "turn off the lights?", {w:1000}], 
     [{di:true}, {d:400}, ". . .", {w:1000}], 
     [{di:true}, {d:40}, "I can't see a thing!", {w:1000}] 
    ]); 
    process.exit(); 
}); 
+0

我不知道。我同意同步控制流量保證是重要的,通常是人們想要的,但我認爲自動屈服可能是有趣的,如果只是作爲一個實驗。如果我知道如何製作預處理器,而不會在錯誤報告中弄亂行/列偏移量,我真的想試一試。 –

+0

有一件事仍然困擾着我:如果我不小心忘記了讓步,我的代碼將會工作,但是異常會被Q吞噬。由於這是一款遊戲,並且這個庫不會產生可恢復的錯誤,所以我會讓'附加一個處理程序,使異常泄漏。如果它們發生,整個遊戲就會崩潰,但是這比靜靜地忽略它們要好... –

+0

呃,那是行不通的。 'Q.done()'就是這樣做的,但我無法確定客戶端代碼('tw'外部的)會使用'.done()'作爲它自己的承諾。所以我仍然必須記得每次都調用它,或者讓步。我真的希望社區找到一種方法來使這個更安全...... :( –