我这怎么能异步回调转换到发电机? [英] How can I convert this async callback to a generator?

查看:165
本文介绍了我这怎么能异步回调转换到发电机?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个很难理解的发电机。但我觉得我想要做的应该是可能的。

我有一个对象主题有权访问秒。本来主题被实现,使得 s就可以通过回调检索。

VAR主题=功能(ID){  变种库=新PageRepository();  this.id = ID;
  this.getAllPages =函数(回调){
    repository.getAllPagesByTopicId(this.id,功能(结果){
      变种页= [];
      而(result.hasNext()){
        pages.push(result.next());
      }
      回调(页);
    });
  }
}VAR话题=新主题(1);
topic.getAllPages(功能(页){
  的console.log(页)//获得页面实例
});

现在,让我们假设我不能重构 PageRepository 的回调机制,但我的的要重构主题,这样我可以访问它是通过一台发电机页,代替通过回调。是可行的,没有太多的hastle?

我知道我可以循环发电机值以为...的语句,如:

VAR话题=新主题(1);
对于(我们()topic.pages页){//创建发电机
  的console.log(页); //收到下一页
}

...所以我的东西,如下面上来的:

VAR主题=功能(ID){  ...  this.pages =功能*(){//重构getAllPages()到发电机的功能页面()
    repository.getAllPagesByTopicId(this.id,功能(结果){
      而(result.hasNext()){
        收率result.next(); //得到下一页
      }
    });
  }
}

不过,这不工作,可能是因为收益从回调中调用。

然后,这篇文章(从要使用发电机......起),我想这可能工作:

VAR主题=功能(ID){  ...  this.pages =功能*(){    让创=功能*(){}(); //创建一个内部产生    //实际上并不知道为什么需要以下包装函数
    //但是类似的观点中提到的文章中使用
    屈服函数(){
      repository.getAllPagesByTopicId(this.id,功能(结果){
        而(result.hasNext()){
          gen.next(result.next()); //调用next()上内发电机
        }
      });
    }(); //立即创建这个神秘的包装函数
  }
}

但是,这也不行,很遗憾。

那么,就是我想实现可行的,没有太多的麻烦;意思是:没有模块(如CO,暂停等)和/或费解的thunk发电机和你有什么


解决方案

  

我要重构主题,这样我可以访问它是通过一台发电机页,代替通过回调。是可行的,没有太多的麻烦?


没有,真的没有。您在这里混合两个概念:


    使用
  • 发电机创建迭代器产生结果值,类似于结果迭代器

  • 滥用,以创建一个迭代产生的异步操作的发电机,即异步从外部驱动,以允许在里面同步控制结构(也见在这里进行更深入的解释,或继续阅读的文章davidwalsh您链接)

有想法,合并这两个概念一旦第二已经得到了自己的关键字,但是这并不适用呢。你被卡住了嵌套的结构,异步回调内部的类似数组的迭代器。

所以,你可以使用任何一台发电机,却没有一个两个。而且它是值得怀疑这是否是值得的。请注意,既不会让你的code同步,你总会在某些方面使用异步回调。


回拨用生成器实例,而不是一个数组:

 函数主题(ID){
  变种库=新PageRepository();
  this.id = ID;
  this.getAllPages =函数(回调){
    repository.getAllPagesByTopicId(this.id,功能(结果){
      回调(功能*(){
        而(result.hasNext()){
          收率result.next();
        }
      }());
    });
  }
}VAR话题=新主题(1);
topic.getAllPages(功能(pageiterator){
  对于(让pageiterator页){
    的console.log(页); //收到下一页
  }
});


不要回拨功能,但恢复发电机(如简单的异步的例子):

 函数主题(ID){
  变种库=新PageRepository();
  this.id = ID;
  this.getAllPages =功能(它){
    repository.getAllPagesByTopicId(this.id,功能(结果){
      为(VAR页= [],result.hasNext())pages.push(result.next());
      it.next(页);
    });
  }
}VAR IT =(功能*(){
  VAR话题=新主题(1);
  VAR页=产量topic.getAllPages(它);
  的console.log(页)//获得页面实例
}());
it.next();

是的,你可以一次使用这两种方法(通过发电机创建迭代器异步发电机的接下来方法),但是这可能是相当混乱。他们会留下来单独的发电机。

I have a hard time understanding generators. But I think what I'm trying to do should be possible.

I have an object Topic that has access to Pages. Originally Topic was implemented such that Pages would be retrieved through a callback.

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
} );

Now, let's assume I cannot refactor PageRepository's callback mechanism, but I do want to refactor Topic such that I can access it's pages through a generator, in stead of through a callback. Is that doable, without too much hastle?

I know I can iterate generator values with a for...of statement, like:

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

... so I came up of with something like the following:

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
      }
    } );
  }
}

However, this doesn't work, probably because yield is called from within the callback.

Then, based my (poor) understandings of this article (from "To use a generator ..." onward), I thought this might work:

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
  }
}

But this doesn't work either, unfortunately.

So, is what I'm trying to achieve doable, without too much hassle; meaning: no modules (like co, suspend, etc...) and/or convoluted thunk generators and what have you?

解决方案

I do want to refactor Topic such that I can access it's pages through a generator, in stead of through a callback. Is that doable, without too much hassle?

No, not really. You are mixing two concepts here:

  • generators used to create iterators yielding result values, similar to the result iterator
  • generators abused to create an iterator yielding asynchronous actions, that is driven asynchronously from the outside to allow synchronous control structures on the inside (see also here for deeper explanation, or continue reading that davidwalsh article you linked)

There are ideas to merge the two concepts once the second has gotten its own keywords, but that's not applicable yet. You are stuck with a "nested" structure, that array-like iterator inside an asynchronous callback.

So you can use a generator for either, but not one for both. And it's questionable whether that's worth it. Notice that neither will make your code synchronous, you will always have to use async callbacks in some regard.


Call back with a generator instance, not an array:

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
  }
} );


Don't call back a function, but resume a generator (like in the simplest async example):

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();

Yes, you can use both approaches at once (passing the generator-created iterator into the next method of the async generator), but that's probably quite confusing. And they'll stay separate generators.

这篇关于我这怎么能异步回调转换到发电机?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆