目录
Promise 的介绍和优点
Promise 对象的用法和状态
使用 Promise 的基本步骤
promise 对象的 3 个状态
Promise 的方法
实例方法
then()
catch()
finally()
静态方法
Promise.resolve()
Promise.reject()
Promise.all()
Promise.race()
还有些其他的
Promise 链式调用(封装多个接口)
?手写promise
几个注意点?
Promise 的介绍和优点
ES6 中的 Promise 是异步编程的一种方案。从语法上讲,Promise 是一个对象,它可以获取异步操作的消息。
Promise 对象, 可以用同步的表现形式来书写异步代码(也就是说,代码看起来是同步的,但本质上的运行过程是异步的)。使用 Promise 主要有以下好处:
Promise 对象的用法和状态
使用 Promise 的基本步骤
(1)通过 new Promise() 构造出一个 Promise 实例。Promise 的构造函数中传入一个参数,这个参数是一个函数,该函数用于处理异步任务。
(2)函数中传入两个参数:resolve 和 reject,分别表示异步执行成功后的回调函数和异步执行失败后的回调函数。代表着我们需要改变当前实例的状态到已完成或是已拒绝。
(3)通过 promise.then() 和 promise.catch() 处理返回结果(这里的 promise 指的是 Promise 实例)。
看到这里,你估计还是不知道 Promise 怎么使用。我们不妨来看一下 Promise 有哪些状态,便一目了然。要知道,Promise 的精髓在于对异步操作的状态管理。
promise 对象的 3 个状态
-
初始化(等待中):pending -
成功:fulfilled -
失败:rejected
步骤 1:
当 new Promise()执行之后,promise 对象的状态会被初始化为pending ,这个状态是初始化状态。new Promise() 这行代码,括号里的内容是同步执行的。括号里可以再定义一个 异步任务的 function,function 有两个参数:resolve 和 reject。如下:
(2)promise.then()方法:只有 promise 的状态被改变之后,才会走到 then 或者 catch。也就是说,在 new Promise()的时候,如果没有写 resolve(),则 promise.then() 不执行;如果没有写 reject(),则 promise.catch() 不执行。
then() 括号里面有两个参数,分别代表两个函数 function1 和 function2:
另外,resolve()和 reject()这两个方法,是可以给 promise.then()传递参数的。
Promise 的方法
实例方法
then()
promise 的then() 方法带有以下三个参数:成功回调,失败回调,前进回调,一般情况下只需要实现第一个,后面是可选的。
p.then(data => {
console.log(data);
});
执行promise 的then() 方法后返回的仍然是一个promise 对象,所以可以进行链式调用
catch()
Promise.prototype.catch() 用于捕获错误,行为与Promise.prototype.then(null, rejection) 的行为一致,用于指定发生错误时的回调函数。
而且,Promise ?对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个?catch ?语句捕获。
finally()
finally() ?方法返回一个Promise 对象。
不管 promise 最后的状态是fulfilled或者是rejected,在执行完then() 或catch() 指定的回调函数以后,都会执行finally() 方法指定的回调函数。
避免了同样的语句需要在then() 和catch() 中各写一次的情况
p.then(data => {
console.log(data);
})
.catch(err => {
console.log(err);
})
.finally(() => {
console.log("finally");
});
静态方法
Promise.resolve()
promise 并非一开始必须处于pending状态,可以使用Promise.resolve() 直接实例化一个已经解决了(处于fulfilled状态)的promise
使用这个静态方法可以将任何值转换成一个promise 值
Promise.reject()
Promise.reject() 会实例化一个拒绝的 promise 并抛出一个异步错误(这个异步错误不能通过try/catch 捕获,而只能通过拒绝处理程序捕获即catch() 方法)
const p_reject = Promise.reject(1);
setTimeout(console.log, 0, p_reject); // Promise { <rejected> 1 }
Promise.all()
Promise.all() 方法接收一个可迭代对象,返回一个Promise 对象,会在这一组Promise 全部解决之后再解决。
const p = Promise.all([Promise.resolve(), Promise.resolve()]);
p.then(() => {
console.log("Promise.all()");
});
Promise.race()
Promise.race() 会返回一个包装promise,是一组集合中最先解决或拒绝的?promise?的镜像。
这个方法接收一个可迭代对象,返回一个新的?promise
const p_race = Promise.race([
Promise.resolve(1),
Promise.reject(2),
Promise.resolve(3),
]);
setTimeout(console.log, 0, p_race); // Promise { 1 }
p_race.then(data => {
console.log(data); // 1
});
还有些其他的
Promise 链式调用(封装多个接口)
// 封装 ajax 请求:传入回调函数 success 和 fail
function ajax(url, success, fail) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('GET', url);
xmlhttp.send();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
success && success(xmlhttp.responseText);
} else {
fail && fail(new Error('接口请求失败'));
}
};
}
// Promise 封装接口1
function request1() {
return new Promise((resolve, reject) => {
ajax('https://www.baidu.com', (res) => {
if (res.retCode == 201) {
// 接口请求成功时调用:这里的 res 是接口1的返回结果
resolve('request1 success' + res);
} else {
// 接口请求异常时调用异常
reject('接口1请求失败');
}
});
});
}
// Promise 封装接口2
function request2() {
return new Promise((resolve, reject) => {
ajax('https://www.jd.com', (res) => {
if (res.retCode == 202) {
// 这里的 res 是接口2的返回结果
resolve('request2 success' + res);
} else {
reject('接口2请求失败');
}
});
});
}
// Promise 封装接口3
function request3() {
return new Promise((resolve, reject) => {
ajax('https://www.taobao.com', (res) => {
if (res.retCode == 203) {
// 这里的 res 是接口3的返回结果
resolve('request3 success' + res);
} else {
reject('接口3请求失败');
}
});
});
}
// 先发起request1,等resolve后再发起request2;紧接着,等 request2有了 resolve之后,再发起 request3
request1()
.then((res1) => {
// 接口1请求成功
console.log(res1);
return request2();
})
.then((res2) => {
// 接口2请求成功
console.log(res2);
return request3();
})
.then((res3) => {
// 接口3请求成功
console.log(res3);
})
.catch((err) => {
// 从 reject中获取异常结果
console.log(err);
});
?手写promise
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function myPromise(constructor) {
let self = this
self.status = 'pending'
self.value = undefined
self.reason = undefined
function resolve(value) {
if (self.status === 'pending') {
self.value = value
self.status = 'resolved'
}
}
function reject(reason) {
if (self.status === 'pending') {
self.reason = reason
self.status = 'rejected'
}
}
try {
constructor(resolve, reject);
} catch (e) {
reject(e);
}
}
myPromise.prototype.then = function (data, err) {
let self = this
switch (self.status) {
case 'resolved':
data(self.value)
break;
case 'rejected':
err(self.reason)
break;
default:
}
}
myPromise.prototype.catch = function (err) {
return this.then(null, err)
}
myPromise.prototype.finally = function (fn) {
return this.then(value => {
fn();
return value
},
reason => {
fn();
return reason
})
}
myPromise.resolve = function (value) {
return new myPromise((resolve, reject) => {
resolve(value);
})
}
myPromise.reject = function (reason) {
return new myPromise((resolve, reject) => {
reject(reason);
})
}
myPromise.all = function (promises) {
return new myPromise((resolve, reject) => {
if (promises.length === 0) {
resolve([])
} else {
let result = [], index = 0
for (let i = 0; i < promises.length; i++) {
promises[i].then(data => {
result[i] = data
if (++index == promises.length) {
resolve(result)
}
}, err => {
reject(err)
return;
})
}
}
})
}
myPromise.race = function (promises) {
return new myPromise((resolve, reject) => {
if (promises.length === 0) {
resolve()
} else {
for (let i = 0; i < promises.length; i++) {
promises[i].then(data => {
resolve(result)
}, err => {
reject(err)
return;
})
}
}
})
}
</script>
</body>
</html>
几个注意点?
- new Promise() 是同步代码
- Promise 的状态一旦改变,就不能再变
|