返回介绍

链式调用

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

“then”函数还有更加巧妙的用法,你可以将修改数值或者添加异步操作的“then”方法串联起来调用,从而让它们按顺序执行。

数值处理

可以简单修改一下原值,然后返回修改结果:

var promise = new Promise(function(resolve, reject) {
  resolve(1);
});

promise.then(function(val) {
  console.log(val); // 1
  return val + 2;
}).then(function(val) {
  console.log(val); // 3
});

我们回到上文的代码继续:

get('story.json').then(function(response) {
  console.log("Success! ", response);
});

我们期望参数 response 是 JSON 格式的数据,但是这里接收到的是纯文本格式。当然,我们可以在 get 函数中修改服务器的响应格式为 JSON,但是也可以在 Promise 代码中做修改来达到相同目的:

get('story.json').then(function(response) {
  return JSON.parse(response);
}).then(function(response) {
  console.log("Yey JSON! ", response);
});

JSON.parse 函数只接受一个参数,并返回转换后的结果。我们根据这个特性来简化一下代码:

get('story.json').then(JSON.parse).then(function(response) {
  console.log("Yey JSON! ", response);
});

可以在开发者工具中的控制台下看到相应的请求结果。其实,我们也可以简单地写一个 getJSON 方法:

function getJSON(url) {
  return get(url).then(JSON.parse);
}

异步操作队列

你可以通过串联“then”方法来依次执行异步操作。

当在“then”方法的回调函数里有返回值的时候,这里有些重要的事情需要我们关注。如果你返回的是一个值,那么下一个“then”会被立即调用,并把这个值传递给它的回调函数。如果你返回的是一个“类 Promise”对象,那么下一个“then”方法会等待执行,直到这个 Promise 被解决(成功或者失败)后才执行。举个例子:

getJSON('story.json').then(function(story) {
  return getJSON(story.chapterUrls[0]);
}).then(function(chapter1) {
  console.log("Got chapter 1! ", chapter1);
});

这里我们对“story.json”发出了一个请求,它会返回一些异步请求的 URL 地址,然后我们又对第一个地址进行了异步请求。现在同简单的事件回调模式相比,Promise 开始显示出自己的优势了。可以像下面这样写个获取章节内容的函数:

var storyPromise;

function getChapter(i) {
  storyPromise = storyPromise || getJSON('story.json');

  return storyPromise.then(function(story) {
    return getJSON(story.chapterUrls[i]);
  })
}

// 使用它很简单


getChapter(0).then(function(chapter) {
  console.log(chapter);
  return getChapter(1);
}).then(function(chapter) {
  console.log(chapter);
});

我们一开始并不请求“story.json”,直到第一次调用 getChapter 方法时才请求,但是后面再调用该方法时会重用已有的 story Promise。因此,story.json 只请求了一次。这大大提高了效率, Promise 真是太棒了!

错误处理

如上文所述,我们知道“then”方法有两个参数,一个是成功后的回调函数,一个是失败后的回调函数(用 Promise 的术语来说,就是 resolve 或者 reject):

get('story.json').then(function(response) {
  console.log("Success! ", response);
}, function(error) {
  console.log("Failed! ", error);
});

你也可以使用“catch”方法:

get('story.json').then(function(response) {
  console.log("Success! ", response);
}).catch(function(error) {
  console.log("Failed! ", error);
});

其实“catch”方法并没有什么特别的地方,它只是 then(undefined, func) 形式的一种语法糖而已,但是它的可读性很好。要注意上面两个例子的表现行为并不一致,后者等同于下面这段代码:

get('story.json').then(function(response) {
  console.log("Success! ", response);
}).then(undefined, function(error) {
  console.log("Failed! ", error);
});

语法差别虽然不大,但是意义重大。Promise 被 reject 后会直接跳转到之后第一个配置了 reject 回调的 then 方法(或者是“catch”方法,二者等价)中。对于 then(func1, func2),只会调用 func1 或 func2 中的一个回调,绝不会两个都被调用。但是 then(func1).catch(func2) 这种形式就不同了,当 func1 中返回 reject 时,func2 也会被调用,这是因为它们分别处于链式调用的不同步骤。请看下面的代码:

asyncThing1().then(function() {
  return asyncThing2();
}).then(function() {
  return asyncThing3();
}).catch(function(err) {
  return asyncRecovery1();
}).then(function() {
  return asyncThing4();
}, function(err) {
  return asyncRecovery2();
}).catch(function(err) {
  console.log("Don't worry about it");
}).then(function() {
  console.log("All done! ");
});

上面的流程非常类似于 JavaScript 中的 try/catch 语句,在“try”代码块中发生的错误会立即跳转到“catch”的代码块中。

发布评论

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