持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第14天,点击查看活动详情
封装Ajax的请求
<body>
<script>
/**
* 封装一个函数 sendAJAX 发送 GET AJAX 请求
* 参数 URL
* 返回结果 Promise 对象
*/
function sendAJAX(url){
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.open("GET", url);
xhr.send();
//处理结果
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
//判断成功
if(xhr.status >= 200 && xhr.status < 300){
//成功的结果
resolve(xhr.response);
}else{
reject(xhr.status);
}
}
}
});
}
sendAJAX('https://api.apiopen.top/getJok')
.then(value => {
console.log(value);
}, reason => {
console.warn(reason);
});
</script>
</body>
Promise 的状态改变
Promise的状态是Promise对象的属性,叫做PromiseState。 他一共有三个值:
- pending 未决定的
- resolved / fullfilled 成功
- rejected 失败
而Promise的状态改变情况只有两种:
- pending 变为 resolved
- pending 变为 rejected
且一个 promise 对象只能改变一次 无论变为成功还是失败, 都会有一个结果数据 成功的结果数据一般称为 value, 失败的结果数据一般称为 reason
Promise对象结果属性
Promise实例对象中还有一个属性PromiseResult
,这个属性中保存着异步任务成功或失败的结果。
这个结果只有两个东西可以进行修改:
- resolve()
- reject()
在这两个函数作出修改之后,在后续的then回调方法中,就又可以把结果给取出来。
Promise的工作流程
Promise的API
Promise 构造函数: Promise (excutor) {} (1) executor 函数: 执行器 (resolve, reject) => {} (2) resolve 函数: 内部定义成功时我们调用的函数 value => {} (3) reject 函数: 内部定义失败时我们调用的函数 reason => {}
说明: executor 会在 Promise 内部==立即同步调用==,异步操作在执行器中执行
Promise.prototype.then 方法: (onResolved, onRejected) => {} (1) onResolved 函数: 成功的回调函数 (value) => {} (2) onRejected 函数: 失败的回调函数 (reason) => {}
说明: 指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调返回一个新的 promise 对象
Promise.prototype.catch 方法: (onRejected) => {} (1) onRejected 函数: 失败的回调函数 (reason) => {}
说明: then()的语法糖,只能指定失败的回调, 相当于: then(undefined, onRejected)
例如:
<script>
//
let p = new Promise((resolve, reject) => {
// ** 同步调用
// console.log(111);
//修改 promise 对象的状态
reject('error');
});
// console.log(222);
//执行 catch 方法
p.catch(reason => {
console.log(reason);
});
</script>
Promise.resolve 方法
Promise.resolve 方法: (value) => {} (1) value: 成功的数据 或 promise 对象 说明: ①返回一个成功/失败的 promise 对象 ②resolve方法是属于Promise的方法,而不是Promise对象的方法。
例如:
<script>
//
let p1 = Promise.resolve(521);
//如果传入的参数为 非Promise类型的对象, 则返回的结果为成功promise对象,并且其结果为传入的参数
//如果传入的参数为 Promise 对象, 则参数的结果决定了 resolve 的结果
let p2 = Promise.resolve(new Promise((resolve, reject) => {
// resolve('OK');
reject('Error');
}));
// console.log(p2);
p2.catch(reason => {
console.log(reason);
})
</script>
如果返回的是错误的Promise对象,那么浏览器会有一个报错,此时可以用catch进行处理。
Promise.reject 方法
Promise.reject 方法: (reason) => {} (1) reason: 失败的原因 说明: 返回一个失败的 promise 对象,失败的结果为传入的值。
例如:
<script>
// let p = Promise.reject(521);
// let p2 = Promise.reject('iloveyou');
let p3 = Promise.reject(new Promise((resolve, reject) => {
resolve('OK');
}));
//即使传入了一个成功的对象他也只会返回一个错误的对象
console.log(p3);
</script>
Promise.all 方法
Promise.all 方法: (promises) => {} (1) promises: 包含 n 个 promise 的数组 说明: 返回一个新的 promise, 只有所有的 promise 都成功才成功, 只要有一个失败了就直接失败。如果成功,则其结果为所有成功Promise对象结果组成的数组,如果失败,则其结果为失败的Promise的结果(不是多个失败的结果,因为第一个失败的时候就直接return了,所以只会返回第一个)。
<script>
let p1 = new Promise((resolve, reject) => {
resolve('OK');
})
// let p2 = Promise.resolve('Success');
let p2 = Promise.reject('Error');
let p3 = Promise.resolve('Oh Yeah');
//
const result = Promise.all([p1, p2, p3]);
console.log(result);
</script>
Promise.race 方法
Promise.race 方法: (promises) => {} (1) promises: 包含 n 个 promise 的数组 说明: 返回一个新的 promise, 第一个完成的 promise 的结果状态就是最终的结果状态
<script>
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK');
}, 1000);
})
let p2 = Promise.resolve('Success');
let p3 = Promise.resolve('Oh Yeah');
//调用
const result = Promise.race([p1, p2, p3]);
console.log(result);
</script>
如何改变 promise 的状态?
要想修改Promise对象的状态,我们有三种办法:
- 用resolve()函数,使状态由pending --> fullfilled
- 用reject()函数,使状态由pending --> rejected
- 抛出错误,使状态由pending --> rejected
例如:
<script>
let p = new Promise((resolve, reject) => {
//1. resolve 函数
// resolve('ok'); // pending => fulfilled (resolved)
//2. reject 函数
// reject("error");// pending => rejected
//3. 抛出错误
// throw '出问题了';
});
console.log(p);
</script>
一个 promise 指定多个成功/失败回调函数, 都会调用吗?
当 promise 改变为对应状态时都会调用
例如:
<script>
let p = new Promise((resolve, reject) => {
// resolve('OK');
});
///指定回调 - 1
p.then(value => {
console.log(value);
});
//指定回调 - 2
p.then(value => {
alert(value);
});
</script>
改变 promise 状态和指定回调函数谁先谁后?
- (1) 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
- (2) 如何先改状态再指定回调? ① 在执行器中直接调用 resolve()/reject() ② 延迟更长时间才调用 then()
- (3) 什么时候才能得到数据? ① 如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据 ② 如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
promise.then()返回的新 promise 的结果状态由什么决定?
(1) 简单表达: 由 then()指定的回调函数执行的结果决定
(2) 详细表达: ① 如果抛出异常, 新 promise 变为 rejected, reason 为抛出的异常 ② 如果返回的是非 promise 的任意值, 新 promise 变为 resolved, value 为返回的值 ③ 如果返回的是另一个新 promise, 此 promise 的结果就会成为新 promise 的结果
例如:
<script>
let p = new Promise((resolve, reject) => {
resolve('ok');
});
//执行 then 方法
let result = p.then(value => {
// console.log(value);
//1. 抛出错误
// throw '出了问题';
//2. 返回结果是非 Promise 类型的对象
// return 521;
//3. 返回结果是 Promise 对象
// return new Promise((resolve, reject) => {
// // resolve('success');
// reject('error');
// });
}, reason => {
console.warn(reason);
});
console.log(result);
</script>
如果没有return则默认返回undefined
promise 如何串连多个操作任务?
(1) promise 的 then()返回一个新的 promise, 可以利用此特点构成 then()的链式调用 (2) 通过 then 的链式调用串连多个同步/异步任务
例如:
<script>
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK');
}, 1000);
});
p.then(value => {
return new Promise((resolve, reject) => {
resolve("success");
});
}).then(value => {
console.log(value);
}).then(value => {
console.log(value); //此value为undefined
})
</script>
promise 异常传透
(1) 当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调, (2) 前面任何操作出了异常, 都会传到最后失败的回调中处理
异常处理的常规逻辑,如果在每一层都对应的去处理相应的异常这很麻烦,我们可以简单的把这些异常汇聚到一个范围一起处理。就跟java异常处理中,我们可以把异常往“上”抛,在一个调用者中进行集中的处理。
例如:
<script>
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK');
// reject('Err');
}, 1000);
});
p.then(value => {
// console.log(111);
throw '失败啦!';
}).then(value => {
console.log(222);
}).then(value => {
console.log(333);
}).catch(reason => {
console.warn(reason);
});
</script>
如何终断Promise链
(1) 当使用 promise 的 then 链式调用时, 在中间中断, 不再调用后面的回调函数 (2) 办法: 在回调函数中返回一个 pendding 状态的 promise 对象(因为then方法只能对状态为fullfilled/rejected的Promise对象进行相应的回调)
例如:
<script>
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK');
}, 1000);
});
p.then(value => {
console.log(111);
//有且只有一个方式
return new Promise(() => {});
}).then(value => {
console.log(222);
}).then(value => {
console.log(333);
}).catch(reason => {
console.warn(reason);
});
</script>