众所周知,Promise是在ES6中新增的异步编程的一种解决方案。而Promise的一些基础用法可以参考一下阮一峰老师的ES6入门。本文主要介绍如何利用Promises使$.ajax()按顺序发起多个请求。
本文的一些代码主要参考了JavaScript Promise迷你书
一般情况下我们都会使用 new Promise() 来创建promise对象,但是除此之外我们也可以使用其他方法。
静态方法Promise.resolve(value) 可以认为是 new Promise() 方法的快捷方式。
比如 Promise.resolve(42); 可以认为是以下代码的语法糖。
new Promise(function(resolve){
resolve(42);
});
在这段代码中的 resolve(42); 会让这个promise对象立即进入确定(即resolved)状态,并将 42 传递给后面then里所指定的 onFulfilled 函数。
方法 Promise.resolve(value); 的返回值也是一个promise对象,所以我们可以像下面那样接着对其返回值进行 .then 调用。
Promise.resolve(42).then(function(value){
console.log(value);
});
promise可以写成方法链的形式
function taskA() {
console.log("Task A");
}
function taskB() {
console.log("Task B");
}
function onRejected(error) {
console.log("Catch Error: A or B", error);
}
function finalTask() {
console.log("Final Task");
}
var promise = Promise.resolve();
promise
.then(taskA)
.then(taskB)
.catch(onRejected)
.then(finalTask);
若在执行时遇到错误,或返回一个onRejected对象,就会执行catch中的代码,然后在执行完catch后,就会进入到finalTask中。
若在执行时未遇到错误或未返回onRejected对象,就会按下面的顺序依次执行:TaskA => TaskB => FinalTask
前面例子中的Task都是相互独立的,只是被简单调用而已。
这时候如果 Task A 想给 Task B 传递一个参数该怎么办呢?
答案非常简单,那就是在 Task A 中 return 的返回值,会在 Task B 执行时传给它。
话不多说,上代码
function doubleUp(value) {
return value * 2;
}
function increment(value) {
return value + 1;
}
function output(value) {
console.log(value);// => (1 + 1) * 2
}
var promise = Promise.resolve(1);
promise
.then(increment)
.then(doubleUp)
.then(output)
.catch(function(err){
// promise chain中出现异常的时候会被调用
console.error(err);
});
这段代码的入口函数是 Promise.resolve(1); ,整体的promise chain执行流程如下所示。
Promise.resolve(1); 传递 1 给 increment 函数
函数 increment 对接收的参数进行 +1 操作并返回(通过return)
这时参数变为2,并再次传给 doubleUp 函数
最后在函数 output 中打印结果
Promise.resolve 方法另一个作用就是将 thenable 对象转换为promise对象。
所谓的thenable对象就像是类数组(Array Like)对象一样,thenable是指一个具有.then方法的对象。
这种将thenable对象转换为promise对象的机制要求thenable对象所拥有的 then 方法应该和Promise所拥有的 then 方法具有同样的功能和处理过程,在将thenable对象转换为promise对象的时候,还会巧妙的利用thenable对象原来具有的 then 方法。
到底什么样的对象能算是thenable的呢,最简单的例子就是 jQuery.ajax(),它的返回值就是thenable的。
因为jQuery.ajax() 的返回值是 jqXHR Object 对象,这个对象具有 .then 方法。
$.ajax(url,parse); // 这个方法的返回值就是一个thenable对象
这个thenable的对象可以使用 Promise.resolve 来转换为一个promise对象。
变成了promise对象的话,就能直接使用 then 或者 catch 等这些在 ES6 Promises里定义的方法了。
由于$.ajax的返回值是一个典型的thenable对象,所以我们可以通过结合Promise与$.ajax()来使通过$.ajax()发起请求更加方便
代码演示如下:
// 这里只设置三个最基本的配置用于演示,而且不用写success
function api(option) { //option是一个对象,用于配置参数
return Promise.resolve($.ajax({
type: option.type,
url: option.url,
data: option.data
}))
}
若需要添加后续操作,也是十分的简单
var option =
{
type: 'post',
url: 'baidu.com',
data: {
a: 123
}
}
api(option)
.then((res) => {
console.log(res) // 将success里面的操作放到这里
})
.catch((err) => {
console.log(err) // 发生错误或返回一个Rejected状态的promise时在这里进行处理
})
若为了使代码便于阅读,可以改写成这样
var option =
{
type: 'post',
url: 'baidu.com',
data: {
a: 123
}
};
function postSuccess (res) {
console.log(res) // 将success里面的操作放到这里
}
function postErr(err) {
console.log(err) // 发生错误或返回一个Rejected状态的promise时在这里进行处理
}
api(option)
.then(postSuccess)
.catch(postErr)
重点来了,如果需要按顺序发起多个请求,可以改造成下面的样子
var option =
{
type: 'post',
url: 'baidu.com',
data: {
a: 123
}
};
function taskASuccess(res) {
console.log(res) // 将success里面的操作放到这里
var option = {
// 可以在这里定义想要传递给taskB的参数,并通过后面的return传递
}
return option
}
function taskB(opt) {
return api(opt)
}
function taskBSuccess(res) {
console.log(res)
}
api(option)
.then(taskASuccess)
.then(taskB)
.then(taskBSuccess) // 若想发起更多请求可以以此类推
.catch((err) => {
console.log(err)
})
看完上面的代码,是不是感觉比传统的回调函数便于阅读多了,若您觉得本篇文章对您有帮助,请帮忙点个关注!!