2014-05-08 46 views
4

我已經閱讀了幾個使用JavaScript生成器的代碼示例such as this one。最簡單的使用發電機組塊我能想出是這樣的:使用yield生成器瞭解代碼流

function read(path) { 
    return function (done) { 
     fs.readFile(path, "file", done); 
    } 
} 

co(function *() { 
    console.log(yield read("file")); 
})(); 

這確實打印出的file的內容,但我掛斷就是done被調用。看起來,yield是語法糖,用於包裝它在回調中返回的內容並適當地分配結果值(並且至少在co的情況下,將錯誤參數引發到回調函數中)。我對語法的理解是否正確?

當使用yield時,done是什麼樣子的?

+0

你指的是'done'作爲內部'讀(路徑)'使用?我不認爲它與'yield'或者具體的發生器有什麼關係 - 它是'co'庫的一部分。 – voithos

回答

2

我發佈了發電機工作原理的詳細說明here

以簡單的形式,你的代碼可能看起來像這樣沒有co(未經測試):

function workAsync(fileName) 
{ 
    // async logic 
    var worker = (function*() { 

     function read(path) { 
      return function (done) { 
       fs.readFile(path, "file", done); 
      } 
     } 

     console.log(yield read(fileName)); 
    })(); 

    // driver 
    function nextStep(err, result) { 
     try { 
      var item = err? 
       worker.throw(err): 
       worker.next(result); 
      if (item.done) 
       return; 
      item.value(nextStep); 
     } 
     catch(ex) { 
      console.log(ex.message); 
      return; 
     } 
    } 

    // first step 
    nextStep(); 
} 

workAsync("file"); 

workAsync通過異步發電機對象迭代,該驅動部分通過調用nextStep()

+0

@ExplosionPills,當調用'item.value(nextStep)'時,'nextStep'與'done'對應,'item.value'對應'read(path)'返回的函數,後者在'worker'生成器內的'yield'語句旁邊被調用。 – Noseratio

3

看似,產率是用於包裹它返回到一個回調和適當地分配的結果值(至少在共同的情況下,引發錯誤參數回調)

語法糖

不,yield不是語法糖。它是生成器的核心語法元素。當這個生成器被實例化時,你可以運行它(通過調用.next()),這將返回return ed或yield ed的值。當發電機爲yield時,您可以稍後再次撥打.next()繼續。 next的參數將是yield表達式在生成器內返回的值。

只有co情況下,這些異步回調的事情(和other things)是什麼,你會考慮自然的異步控制流圖書館「適當」處理。

使用良率時的做法是什麼?

article that you readthread功能例子給你一個很好的印象:

function thread(fn) { 
    var gen = fn(); 
    function next(err, res) { 
    var ret = gen.next(res); 
    if (ret.done) return; 
    ret.value(next); 
    } 
    next(); 
} 

在你的代碼,yield確實當它跑到離發生器產生表達read("file")的價值。這成爲ret.valgen.next()的結果。爲此,next函數被傳遞 - 一個回調函數,它將繼續生成器並傳遞給它的res ult。在您的生成器代碼中,看起來好像yield表達式返回了此值。

的「展開」發生了什麼版本可以這樣寫:

function fn*() { 
    console.log(yield function (done) { 
     fs.readFile("filepath", "file", done); 
    }); 
} 
var gen = fn(); 
var ret1 = gen.next(); 
var callasync = ret1.value; 
callasync(function next(err, res) { 
    var ret2 = gen.next(res); // this now does log the value 
    ret2.done; // true now 
}); 
+0

@Noseratio:對不起,我不太明白你的意思。 「分配給'.value」的必要條件是什麼?不是從'yield'表達式返回的參數傳遞給'.next()'嗎?如果需要更正,請隨時編輯我的帖子。 – Bergi

+1

抱歉,無視我最後的評論,我錯了。 +1。 – Noseratio

+0

@Bergi我還是有點困惑;什麼是實際*完成*功能?這是傳入'callasync'嗎? 'yield'會發出'ret2'的值?爲什麼? –