Slowdown due to non-parallel awaiting of promises in async generators

后端 未结 3 751
隐瞒了意图╮
隐瞒了意图╮ 2020-11-27 06:02

I\'m writing code using generators and Bluebird and I have the following:

var async = Promise.coroutine;
function Client(request){
    this.request = request         


        
3条回答
  •  暖寄归人
    2020-11-27 06:54

    You are spending too much time waiting for I/O from different sources.

    In normal promise code, you'd use Promise.all for this, however - people have a tendency to write code that waits for requests with generators. Your code does the following:

    <-client     service->
    countryFor..
               ''--..
                  ''--..
                     ''--.. country server sends response
                   ..--''
              ..--''
         ..--''
    getCommentDataFor
         ''--..
               ''--..
                   ''--..
                         ''--.. comment service returns response
                    ..--''
              ..--''
          ..--''
    authenticate
           ''--..
                ''--..
                      ''--.. authentication service returns
                 ..--''
           ..--''
     ..--''
     Generator done.
    

    Instead, it should be doing:

    <-client     service->
    countryFor..
    commentsFor..''--..
    authenticate..''--..''--..
                     ''--..''--..''--.. country server sends response
                            ''--..--''..  comment service returns response
                       ..--''..--''..     authentication service returns response
              ..--''..--''..
     ..--''..--''..--''
     ..--''..--''
     ..--''
     Generator done
    

    Simply put, all your I/O should be done in parallel here.

    To fix this, I'd use Promise.props. Promise.props takes an objects and waits for all its properties to resolve (if they are promises).

    Remember - generators and promises mix and match really well, you simply yield promises:

    Client.prototype.fetchCommentData = async(function* (user){
        var country = countryService.countryFor(user.ip);
        var data = api.getCommentDataFor(user.id);
        var notBanned = authServer.authenticate(user.id).then(function(val){
              if(!val) throw new AuthenticationError(user.id);
        });
        return Promise.props({ // wait for all promises to resolve
            country : country,
            comments : data,
            notBanned: notBanned
        });
    });
    

    This is a very common mistake people make when using generators for the first time.

    ascii art shamelessly taken from Q-Connection by Kris Kowal

提交回复
热议问题