欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

js异步编程三、生成器函数、Gennerator、Async/Await语法糖

程序员文章站 2022-04-30 09:10:04
...

生成器函数就是在普通函数上多了上*号,当调用这个生成器函数的时候不会立即执行函数,而且得到一个生成器对象,直接手动的调用这个生成器的next方法,这个函数的函数体才会开始执行。
在函数的内容可以使用yield的关键词向外返回一个值,在next方法调用的时候可以拿到这个值,在返回的对象中还有个done属性,用来表示这个生成器是否已经全部执行完,而且yield关键词并不会像return一样立即结束函数,只是暂停这个生成器函数,直到下一次调用next方法会继续从yield位置向下执行。
如果给next传参数,会做成yield语句的返回值.

function* foo() {
  console.log("start");

  const res = yield "foo";
  console.log(res);
}

const generator = foo();
const result = generator.next();
console.log(result);

js异步编程三、生成器函数、Gennerator、Async/Await语法糖
如果说在外部调用的是生成器throw方法,那这个方法就可以对生成器函数内部抛出一个异常.

function* foo() {
  console.log("start");
  try {
    const res = yield "foo";
    console.log(res);
  } catch (e) {
    console.log(e);
  }
}

const generator = foo();
const result = generator.next();
console.log(result);

generator.throw(new Error("Generator error"));

js异步编程三、生成器函数、Gennerator、Async/Await语法糖
Gennerator异步方案(生成器函数):

function ajax(url) {...}
function* main() {
  const user = yield ajax(user.json);
  console.log(users);
}

const g = main();
const result = g.next();

result.value.then(data => {
  g.next(data);
});

用这种方法彻底的消灭了promise的回调,有了近乎于同步代码的体验。多个接口时可以在main中做多个yield的操作。在外部第二次调用的结果也是一个promise对象,一样的接收到value再调用里面的then方法。

function ajax(url) {...}
function* main() {
  const user = yield ajax(user.json);
  console.log(users);

  const posts = yield ajax(posts.json);
  console.log(posts);
}

const g = main();
const result = g.next();

result.value.then(data => {
  const result2 = g.next(data);
  result2.value.then(data => {
    g.next(data);
  });
});

直到返回的done属性为true,说明main方法里执行完,可以用递归的方式,直接done为true结束函数.可以把这个封装成公共的函数。

function ajax(url) {...}
function* main() {
  const user = yield ajax(user.json);
  console.log(users);

  const posts = yield ajax(posts.json);
  console.log(posts);
}

function co(gennerator) {
  const g = generator();
  function handleResult(result) {
    if (result.done) return; //生成器函数结束
    result.value.then(
      data => {
        handleResult(g.next(data));
      },
      error => {
        g.throw(error);
      }
    );
  }
  handleResult(g.next());
}

co(main);

像这样的生成器函数执行器在社区中就有一个更完善的co库

也可以直接使用Async/Await语法糖(语言层面的异步编程标准)

async function main() {
  try {
    const user = await ajax(user.json);
    console.log(users);

    const posts = await ajax(posts.json);
    console.log(posts);
  } catch (e) {
    console.log(e);
  }
}

async最大的好处是不需要配合类似于co这样的执行器,因为这是标准语言层面的异步编程语法,其次async函数会返回一个promise对象,更加利于对整体代码的控制。注意await关键词只能出现在async内部