在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 問答/網(wǎng)絡(luò)安全  HTML/ 在node.js中,如果用yield控制并發(fā)操作

在node.js中,如果用yield控制并發(fā)操作

問題背景:

我用的是egg1.x,基于koa。然后就是各種generator,各種yield調(diào)用。這樣的好處是編碼舒服,都是同步代碼。缺點是在某些情況下,速度會異常緩慢。比如有些邏輯需要基于http協(xié)議循環(huán)調(diào)用另外的服務(wù)。egg官網(wǎng)上提供了一種基于yield的控制并發(fā)方法,代碼如下:

const [ news, user ] = yield [
  ctx.service.news.list(topic),
  ctx.service.user.get(uid),
];

這是一種極度簡單的使用場景。它無法控制并發(fā)量。所以我把它改造成了如下代碼:

      const concurrency = 5;
      let index = 0;
      let tempArr = [];
      for (const item of data) {
        tempArr.push(ctx.service.user.get(item.uid));
        if (index === concurrency) {
          yield tempArr;
          tempArr = [];
          index = 0;
        }
        index++;
      }
      if (tempArr.length) {
        yield tempArr;
      }

這樣寫確實可以達到效果,當(dāng)然如果需要處理返回值,會更復(fù)雜一點。但是本人水平有限,想不出什么辦法將這個方法進行封裝。所以想問的第一個問題便是如何封裝它。

async的maplimit

在async的文檔上找到如下代碼

async.mapLimit(urls, 5, async function(url) {
    const response = await fetch(url)
    return response.body
}, (err, results) => {
    if (err) throw err
    // results is now an array of the response bodies
    console.log(results)
})

這不就是我夢寐以求的嗎?然而無情的現(xiàn)實是公司目前并不想升級nodejs,所以還是得乖乖用generator。后來我又想把上面的代碼改造成generator/yield

async.mapLimit(urls, 5, function* (url) {
    const response = yield fetch(url)
    return response.body
}, (err, results) => {
    if (err) throw err
    // results is now an array of the response bodies
    console.log(results)
})

然而一個回調(diào)函數(shù)都執(zhí)行不了。所以第二個問題是為啥不能直接改造呢,async不是generator的語法糖嗎?

回答
編輯回答
涼薄

async是generator的語法糖,但不是簡單的替換就可以解決的
使用await語法自帶執(zhí)行器,而generator則是不帶執(zhí)行器,需要自己手工添加
await需要后面的變量是一個promise對象

給你個generator+promise對 async/await的實現(xiàn)

//一個generator執(zhí)行器的實現(xiàn)
function run(generator){
    var gen=generator();
    var resultValue=gen.next();
    if(resultValue.done){
        return resultValue.value;
    }

    function runGenerator(value){
        Promise.resolve(value).then(function(data){
            var resultValue=gen.next(data);
            if(!resultValue.done){
                runGenerator(resultValue.value);
            }
        }).catch(function(error){
            gen.throw(new Error(error));
        });
    }

    return runGenerator(resultValue.value);
}

//執(zhí)行執(zhí)行器,
//傳入一個generator函數(shù),yield后面帶一個promise對象
run(function *(){
    var task1=function(){
        return new Promise(function(resolve,reject){
            setTimeout(function(){
                console.log("1000");
                resolve("1000");
            },1000);
        });
    };

    var task2=function(data){
        return new Promise(function(resolve,reject){
            setTimeout(function(){
                console.log("2000 :: "+data+"");
                resolve("2000 :: "+data+"");
            },1000);
        });
    };

    try{

        var data=yield task1();
        var data2=yield task2(data);

        return data2;
    }catch(error){
        console.log("~~~~error~~~");
    }

});
2017年3月6日 22:42
編輯回答
失心人

第一個問題:
co-parallel

第二個問題:
你需要把 function*(url){} 用 co 包一下。generator 并不會自動執(zhí)行,某種程度上你可以把 async 函數(shù)視為自動幫你 co 一下了的 generator。
但是不確定你這么寫能不能執(zhí)行,待會測試一下。

2018年8月18日 05:10
編輯回答
未命名
const co = require('co');
function mapLimit(urls, limit, genFn, cb) {
  co(function* () {
    let results = [];
    while(urls.length) {
      let res = yield urls.splice(0, limit).map(genFn);
      results.push(...res);
    }
    return results;
  }).then(function(res) {
    cb(null, res)
  }).catch(cb)
}

這樣封裝樓主看看能嗎
async.mapLimit官方文檔里要求傳asyncFUnction函數(shù),傳Generator肯定不行了

2017年2月14日 07:34