ES6发电机 - 他们真的可以替代异步/等待吗?

时间:2014-12-01 20:44:52

标签: javascript typescript async-await generator ecmascript-6

this 打字稿博客文章评论部分中的一篇帖子说:

  

如果我必须等到2.0才能获得ES6发电机支持,我就是这样   坚持Traceur。发电机是一个大问题,他们给你   async / await支持今天使用Koa,Co,Bluebird等库,   等

Async / await关键字将允许应用程序保留类似于同步代码的逻辑结构。如何使用发电机来完成类似的事情呢?例如,如何将生成器与ajax调用结合使用以生成避免使用回调的同步样式代码?

3 个答案:

答案 0 :(得分:5)

你只需要用辅助函数来抽象它。

假设jQuery:

function ajax(type, url, data){
  $.ajax({
    url: url,
    data: data,
    type: type
  })
  .done(function(data) {
    iterator.next(data);
  })
  .fail(function() {
    iterator.throw();
  });
}
var get = ajax.bind(null, 'GET');
var post = ajax.bind(null, 'POST');
var put = ajax.bind(null, 'PUT');
var patch = ajax.bind(null, 'PATCH');
var del = ajax.bind(null, 'DELETE');

function *asyncGet() {
  var URL = 'https://api.stackexchange.com/2.2/answers?order=desc&sort=activity&site=stackoverflow'
  var data = yield get(URL);
  console.log(data);
}

var iterator = asyncGet();
iterator.next();

使用setTimeout的另一个例子:

function delayReturn(time, val){
  setTimeout(function(){
    iterator.next(val);
  }, time);
}
var delayReturn1s = delayReturn.bind(null, 1000);

function *main() {
  console.log(yield delayReturn1s('Lolcat'));
}

var iterator = main();
iterator.next()

当然,您可以使用以下内容抽象迭代器:

var async = function(generator){
  var resume = function(err, data){
    if (err) iterator.throw();
    iterator.next(data);
  }
  var iterator = generator(resume);
  iterator.next();
}

然后你可以简单地说:

function ajax(type, url, data, cb){
  $.ajax({
    url: url,
    data: data,
    type: type
  })
  .done(function(data) {
    cb(null, data)
  })
  .fail(function() {
    cb(arguments);
  });
}
var get = ajax.bind(null, 'GET');
var post = ajax.bind(null, 'POST');
var put = ajax.bind(null, 'PUT');
var patch = ajax.bind(null, 'PATCH');
var del = ajax.bind(null, 'DELETE');

async(function *(resume) {
  var URL = 'https://api.stackexchange.com/2.2/answers?order=desc&sort=activity&site=stackoverflow'
  var data = yield get(URL, null, resume);
  console.log(data);
});

答案 1 :(得分:1)

  

例如,如何将生成器与ajax调用结合使用以生成避免使用回调的同步样式代码?

来自Beginning Node.js


作为一个思想实验想象如下,一种告诉JavaScript运行时暂停执行承诺上使用的await关键字上的代码并且仅恢复 一次(以及如果)返回的承诺的方法从功能上解决了。

// Not actual code. A thought experiment
async function foo() {
    try {
        var val = await getMeAPromise();
        console.log(val);
    }
    catch(err){
        console.log('Error: ',err.message);
    }
}

当承诺结束继续执行时,如果它已经完成,那么await将返回该值,如果它被拒绝,将同步抛出错误,我们可以捕获。这突然(并且神奇地)使异步编程像同步编程一样简单。需要做三件事:

  • 暂停功能执行的能力。
  • 能够在函数内返回一个值。
  • 能够在函数内部抛出异常。

好消息是这种魔法非常真实,今天可以尝试。语法略有不同,因为我们将使用的技术不仅仅是为此而设计的。这可能是因为JavaScript生成器,ECMAScript 6附带的技术,您今天可以使用它。


生成器允许您暂停函数执行(使用yield关键字)返回一个值(使用.next(val)函数)并抛出异常(使用.throw(err)函数) 。书中解释了这些API,您也可以在生成器文档中查看它们。即使你不了解确切的API,你仍然应该获得积分/力量,因为你现在知道相关性。

答案 2 :(得分:1)

来自Thomas Hunter的博文The long road to Async/Await in JavaScript

第3阶段:生成器/产量(ES6)显示了使用ES6生成器执行异步JavaScript的示例。但是,这仅用于演示,很可能您不想使用此技术。使用 async / 等待而不是ES7(实验性)到ES5 traspiler,如Babel或TypeScript。

var generator = publishLevel(12, {data: true});

generator.next().value.then(function(user) {
   return generator.next(user).value.then(function(can_create) {
     return generator.next(can_create).value.then(function(level_result) {
       console.log(level_result);
     });
   });
 });

function * publishLevel(user_id, level_data) {
  var user = yield getUser(user_id);
  var can_create = yield canCreate(user);

  if (!can_create) {
    return null;
  }

  var level = yield saveLevel(user, level_data);

  return level;
}

function getUser(user_id) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve({
        id: user_id,
        nickname: 'tlhunter'
      });
    }, 100);
  });
}

function canCreate(user) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve(user.id === 12);
    }, 100);
  });
}

function saveLevel(user, data) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve({
        id: 100,
        owner: user.nickname,
        data: data
      });
    }, 100);
  });
}