簡體   English   中英

如何將該異步回調轉換為生成器?

[英]How can I convert this async callback to a generator?

我很難理解發電機。 但我認為我想做的應該是可能的。

我有一個可以訪問Page的對象Topic 最初實現Topic是為了通過回調來檢索Page

var Topic = function( id ) {

  var repository = new PageRepository();

  this.id = id;
  this.getAllPages = function( callback ) {
    repository.getAllPagesByTopicId( this.id, function( result ) {
      var pages = [];
      while( result.hasNext() ) {
        pages.push( result.next() );
      }
      callback( pages );
    } );
  }
}

var topic = new Topic( 1 );
topic.getAllPages( function( pages ) {
  console.log( pages ) // received Page instances
} );

現在,假設我無法重構PageRepository的回調機制,但我確實希望重構Topic ,以便可以通過生成器而不是通過回調來訪問它的頁面。 在沒有太多草草的情況下,這是否可行?

我知道我可以使用for...of語句來迭代生成器值,例如:

var topic = new Topic( 1 );
for( let page of topic.pages() ) {  // create the generator
  console.log( page ); // received next Page
}

...所以我想到了以下內容:

var Topic = function( id ) {

  ...

  this.pages = function*() { // refactored getAllPages () to a generator function pages()
    repository.getAllPagesByTopicId( this.id, function( result ) {
      while( result.hasNext() ) {
        yield result.next(); // yield the next Page
      }
    } );
  }
}

但是,這不起作用,可能是因為在回調內部調用了yield

然后,基於我對本文的 (較差的)理解(從“要使用生成器...”開始),我認為這可能有效:

var Topic = function( id ) {

  ...

  this.pages = function*() {

    let gen = function*() {}(); // create an inner generator

    // not actually sure why the following wrapper function is needed
    // but something similar is used in mentioned article
    yield function() {
      repository.getAllPagesByTopicId( this.id, function( result ) {
        while( result.hasNext() ) {
          gen.next( result.next() ); // call next() on inner generator
        }
      } );
    }(); // immediately create this mysterious wrapper function
  }
}

不幸的是,但這也不起作用。

因此,這就是我試圖實現的目標,而沒有太多麻煩; 含義:沒有模塊(例如co,suspend等)和/或卷積的thunk生成器,您呢?

我確實希望重構Topic ,以便可以通過生成器而不是通過回調來訪問它的頁面。 這樣做沒有太多麻煩嗎?

不,不是。 您在這里混合了兩個概念:

  • 生成器,用於生成產生結果值的迭代器,類似於result迭代器
  • 生成器被濫用來創建產生異步操作的迭代器,該迭代器從外部異步驅動以允許內部具有同步控制結構(另請參見此處以獲取更詳細的說明 ,或者繼續閱讀您鏈接的davidwalsh文章)

一旦第二個概念有了自己的關鍵字( async / await ),就有一些想法可以合並這兩個概念 ,但這還不適用( 異步迭代建議在第3階段)。 您將陷入“嵌套”結構,即異步回調內部的類似於數組的迭代器。

因此,您可以為任何一個使用生成器,但不能同時使用兩者。 這是否值得懷疑。 請注意,這兩者都不會使您的代碼同步,因此您在某些方面始終必須使用異步回調。


使用生成器實例而不是數組進行回調:

function Topic( id ) {
  var repository = new PageRepository();
  this.id = id;
  this.getAllPages = function( callback ) {
    repository.getAllPagesByTopicId( this.id, function( result ) {
      callback( function* () {
        while( result.hasNext() ) {
          yield result.next();
        }
      }() );
    } );
  }
}

var topic = new Topic( 1 );
topic.getAllPages( function( pageiterator ) {
  for( let page of pageiterator ) {
    console.log( page ); // received next Page
  }
} );

不要回調函數,而是恢復生成器(如最簡單的異步示例):

function Topic( id ) {
  var repository = new PageRepository();
  this.id = id;
  this.getAllPages = function( it ) {
    repository.getAllPagesByTopicId( this.id, function( result ) {
      for (var pages = [], result.hasNext(); ) pages.push( result.next() );
      it.next( pages );
    } );
  }
}

var it = (function *() {
  var topic = new Topic( 1 );
  var pages = yield topic.getAllPages( it );
  console.log( pages ) // received Page instances
}());
it.next();

是的,您可以同時使用這兩種方法(將生成器創建的迭代器傳遞到異步生成器的next方法中),但這可能很令人困惑。 他們將保持獨立的發電機。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM