使用 JavaScript Promise 读取 Github 用户数据

作者:闭包旅人时间:2026-10-25 18:27:05浏览:333

本文详解如何使用 JavaScript Promise 链式调用读取 GitHub 用户数据。通过封装 fetch 请求、处理 JSON 响应及异步显示头像,展示如何构建可扩展的异步流程。重点解析 Promise 状态传递、链式执行机制及代码重构技巧,帮助开发者掌握现代前端异步编程的核心模式。

Promise 链式调用的基本执行机制

代码如下:

// Make a request for user.json
fetch('/article/promise-chaining/user.json')
  // Load it as json
  .then(response => response.json())
  // Make a request to GitHub
  .then(user => fetch(`https://api.github.com/users/${user.name}`))
  // Load the response as json
  .then(response => response.json())
  // Show the avatar image (githubUser.avatar_url) for 3 seconds (maybe animate it)
  .then(githubUser => {
    let img = document.createElement('img');
    img.src = githubUser.avatar_url;
    img.className = "promise-avatar-example";
    document.body.append(img);

    setTimeout(() => img.remove(), 3000); // (*)
  });

这段代码的逻辑非常直观:每次调用 then 方法都会返回一个新的 Promise 对象。这意味着,后续的 then 调用必须等待前一个 then 返回的 Promise 状态变为 resolved(已解决)后,才会开始执行。

解决原始代码的缺陷:返回 Promise

然而,上述代码存在一个明显的缺陷:

观察 * 所在行的代码:在头像图片显示完毕并被移除后,如果我们希望添加额外的处理逻辑,该如何操作?例如,我们可能希望在头像消失后,显示一个用于编辑该用户信息或其他内容的表单。

为了让这个处理链具备可扩展性,我们需要返回一个 Promise,该 Promise 会在头像显示完成后被 resolve。

修改后的代码如下:

fetch('/article/promise-chaining/user.json')
  .then(response => response.json())
  .then(user => fetch(`https://api.github.com/users/${user.name}`))
  .then(response => response.json())
  .then(githubUser => new Promise(function(resolve, reject) { // (*)
    let img = document.createElement('img');
    img.src = githubUser.avatar_url;
    img.className = "promise-avatar-example";
    document.body.append(img);

    setTimeout(() => {
      img.remove();
      resolve(githubUser); // (**)
    }, 3000);
  }))
  // triggers after 3 seconds
  .then(githubUser => alert(`Finished showing ${githubUser.name}`));

此时,(*) 行中的 .then 处理程序返回了一个新的 Promise。这个新 Promise 只有在 setTimeout (**) 中调用 resolve(githubUser) 之后才会被解决。链中的下一个 .then 将等待这个新的 Promise 完成。

下图第 5 行创建了一个新的 Promise 对象,该对象在第 13 行被 resolve。这个 resolve 操作会触发等待它的第 17 行的 then 方法。

Promise 链式调用的基本执行机制

作为一种良好的编程实践,异步操作应当始终返回一个 Promise。这使得后续的操作计划成为可能;即使当前我们并不打算扩展链,未来也可能需要这种灵活性。

代码重构:封装异步操作

最后,我们对代码进行重构。

function loadJson(url) {
  return fetch(url)
    .then(response => response.json());
}

上述函数返回一个 Promise,当 response 的 json 数据可用时,后注册的 .then 函数就会被触发。

查看其消费代码:

Promise 链式调用的基本执行机制

当 26 行 then 里的箭头函数触发时,user 变量即为 25 行 user.json 数据经过反序列化后形成的 JSON 对象。

function loadGithubUser(name) {
  return loadJson(`https://api.github.com/users/${name}`);
}

这仅仅是对 loadJson 的一层封装,目的是让调用者无需了解 Github user api 的具体 endpoint 地址。

function showAvatar(githubUser) {
  return new Promise(function(resolve, reject) {
    let img = document.createElement('img');
    img.src = githubUser.avatar_url;
    img.className = "promise-avatar-example";
    document.body.append(img);

    setTimeout(() => {
      img.remove();
      resolve(githubUser);
    }, 3000);
  });
}

函数返回一个 Promise,在 executor 中编写业务逻辑,并通过 resolve(githubUser) 将 Promise 状态设置为 fulfilled,以便未来的扩展。

最终的完整代码如下:

// Use them:
loadJson('/article/promise-chaining/user.json')
  .then(user => loadGithubUser(user.name))
  .then(showAvatar)
  .then(githubUser => alert(`Finished showing ${githubUser.name}`));
  // ...

Promise 链状态传递总结

总结:

如果 .then(或 catch/finally,具体使用哪个无关紧要)处理程序返回一个 Promise,则 Promise 链的其余部分会一直等待,直到这个 pending(挂起)状态的 Promise 被 resolve。当 Promise 内部的 executor 有数据被 resolve 调用时,resolve 输入的数据(或错误)会被进一步传递到 Promise chain 里的其他 Promise.then 中。

Promise 链式调用的基本执行机制

到此这篇关于使用 JavaScript Promise 读取 Github 用户数据的文章就介绍到这了,更多相关 JavaScript Promise 读取内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

作者最新文章