返回介绍

Promise 和 Generator

发布于 2025-04-26 18:09:29 字数 2385 浏览 0 评论 0 收藏

接下来的内容会涉及 ES6 的一些新特征,它对你在代码中使用 Promsie 会产生很大影响,但是不用担心,只需要把它们看做即将上映的大片预告即可。

ES6 给我们带来了 Generator,它允许函数在特定的位置像“return”一样退出,稍后又可以在这个特殊位置恢复先前状态继续执行:

function *addGenerator() {
  var i = 0;
  while (true) {
    i += yield i;
  }
}

注意函数名前的星号,这表明该函数是一个 Generator。关键字 yield 标记了暂停/恢复状态的特殊位置。我们可以像这样来使用:

var adder = addGenerator();
adder.next().value; // 0
adder.next(5).value; // 5
adder.next(5).value; // 10
adder.next(5).value; // 15
adder.next(50).value; // 65

但是,这些跟 Promise 有什么关系?其实,你可以用这种暂停/继续的机制写出形如同步(理解起来也简单),但是效果是异步的代码。你不必纠结于下面这个辅助函数中每行代码的具体含义,它让我们可以使用 yield 来等待其中 Promise 的完成:

function spawn(generatorFunc) {
  function continuer(verb, arg) {
    var result;
    try {
      result = generator[verb](arg);
    } catch (err) {
      return Promise.reject(err);
    }
    if (result.done) {
      return result.value;
    } else {
      return Promise.resolve(result.value).then(onFulfilled,
          onRejected);
    }
  }
  var generator = generatorFunc();
  var onFulfilled = continuer.bind(continuer, "next");
  var onRejected = continuer.bind(continuer, "throw");
  return onFulfilled();
}

这段代码从 Q 中引用而来,只是被改成了 JavaScript Promise 的形式。我们把上面最终的示例代码同 ES6 的一些特性结合改造后,产生了下面的代码:

spawn(function *() {
  try {
    // 'yield' 执行一个异步的等待,


    // 返回这个

 Promise 的结果


    let story = yield getJSON('story.json');
    addHtmlToPage(story.heading);

    // 把章节

 url 数组转换成对应的

 Promise 数组


    // 保证所有内容并行加载


    let chapterPromises = story.chapterUrls.map(getJSON);

    for (let chapterPromise of chapterPromises) {
      // 等待每一章节加载完毕,将内容添加到页面上


      let chapter = yield chapterPromise;
      addHtmlToPage(chapter.html);
    }

    addTextToPage("All done");
  }
  catch (err) {
    // 使用

 try/catch 即可,否定的

 Promise 会在这里被抛出


    addTextToPage("Argh, broken: " + err.message);
  }
  document.querySelector('.spinner').style.display = 'none';
});

这同前文例子的功能完全一样,但是更加容易理解。这个例子目前可以在 Chrome 和 Opera 下运行,但是你需要先在 about:flags 中开启 Enable experimental JavaScript 的选项。

这里使用了一堆 ES6 的新语法:Promise、Generator、let、for-of。当我们在一个 Promise 上使用 yield 时,spawn 函数会等待 Promise 的完成,然后返回最终的结果值。如果 Promise 被 reject,则 spawn 中的 yield 会抛出一个异常,同时我们会用正常的 JavaScript try/catch 将其捕获后进行处理。天哪,这样写异步代码真是太简单了!

这种编程模式非常有用,它会在 ES7 中以异步函数的形式来体现,实现方式同上面的代码非常相似,只是不再需要 spawn 方法来辅助实现了。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。