ES6基础知识点 — Promise
1、Promise的简单介绍和基本使用
Promise是异步编程的一种解决方案。
why需要引入Promise
在开发项目的过程中,我们可能需要发送网络请求,由于网络请求是一个异步事件,不能立即拿到结果,所以我们会封装一个网络请求函数,并传入一个回调函数,当数据请求成功时,将数据通过传入的函数回调出去。这种方案虽然也能拿到我们想要的数据,但是一旦网络请求非常复杂时,就会出现回调地狱,导致代码的可读性很差。而使用promise就能很好的解决地狱回调的问题。
这里使用简单的例子来说明:
以setTimeout来模拟异步请求,如果不使用promise,则
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise的基本使用</title>
</head>
<body>
<script>
// 1.发送第一次请求
setTimeout(() => {
console.log('first, 我是第一次请求!!!');
console.log('first, 我是第一次请求!!!');
console.log('first, 我是第一次请求!!!');
console.log('first, 我是第一次请求!!!');
// 2.发送第二次请求
setTimeout(() => {
console.log('second, 我是第二次请求!!!');
console.log('second, 我是第二次请求!!!');
console.log('second, 我是第二次请求!!!');
console.log('second, 我是第二次请求!!!');
console.log('second, 我是第二次请求!!!');
// 3.发送第三次请求
setTimeout(() => {
console.log('third, 我是第三次请求!!!');
console.log('third, 我是第三次请求!!!');
console.log('third, 我是第三次请求!!!');
console.log('third, 我是第三次请求!!!');
console.log('third, 我是第三次请求!!!');
console.log('third, 我是第三次请求!!!');
console.log('third, 我是第三次请求!!!');
}, 3000)
}, 2000)
}, 1000)
</script>
</body>
</html>
显示效果:
在使用过程中,我们发现,代码嵌套真的是太严重了,如果有多个请求,那么代码的可读性是很差的,so,我们可以使用promise来进行异步请求的处理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise的基本使用</title>
</head>
<body>
<script>
new Promise((resolve, reject) => {
// 1.发送第一次请求
setTimeout(() => {
resolve();
}, 1000)
}).then(() => {
// 处理第一次请求
console.log('first, 我是第一次请求!!!');
console.log('first, 我是第一次请求!!!');
console.log('first, 我是第一次请求!!!');
console.log('first, 我是第一次请求!!!');
// 2.发送第二次请求
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 2000)
}).then(() => {
// 处理第二次请求
console.log('second, 我是第二次请求!!!');
console.log('second, 我是第二次请求!!!');
console.log('second, 我是第二次请求!!!');
console.log('second, 我是第二次请求!!!');
console.log('second, 我是第二次请求!!!');
// 3.发送第三次请求
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 3000)
}).then(() => {
// 处理第三次请求
console.log('third, 我是第三次请求!!!');
console.log('third, 我是第三次请求!!!');
console.log('third, 我是第三次请求!!!');
console.log('third, 我是第三次请求!!!');
console.log('third, 我是第三次请求!!!');
console.log('third, 我是第三次请求!!!');
console.log('third, 我是第三次请求!!!');
})
})
})
</script>
</body>
</html>
显示效果:
简单介绍一下Promise
在执行Promise时,会传入两个参数:resolve, reject。而它们本身又是函数
Promise是一种链式编程,下面以一个例子展示Promise的使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise的基本使用</title>
</head>
<body>
<script>
new Promise((resolve, reject) => {
// 模拟发送网络请求
setTimeout(() => {
// 1.请求成功时调用 resolve()
resolve('hello, success. YiBo');
// // 2.请求失败时调用 reject()
// reject('err, you are wrong')
}, 1000)
}).then((data) => {
// 获取到resolve中传入的数据
console.log(data);
}).catch((err) => {
// 获取到reject中的数据
console.log(err);
})
</script>
</body>
</html>
显示效果:
请求失败时的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise的基本使用</title>
</head>
<body>
<script>
new Promise((resolve, reject) => {
// 模拟发送网络请求
setTimeout(() => {
// 1.请求成功时调用 resolve()
// resolve('hello, success. YiBo');
// 2.请求失败时调用 reject()
reject('err, you are wrong')
}, 1000)
}).then((data) => {
// 获取到resolve中传入的数据
console.log(data);
}).catch((err) => {
// 获取到reject中的数据
console.log(err);
})
</script>
</body>
</html>
显示效果:
2、Promise的三种状态
Promise有三种状态:
- pending:等待状态。eg:比如正在进行网络请求,或者定时器没有到时间
- fulfilled:当调用resolve(),成功,状态会由 pending 转换为 fulfilled 状态
- rejected:当调用reject(),失败,状态会由 pending 转换为 rejected 状态
3、Promise的另外处理方式
在Promise的.then()中,也可以处理请求失败的数据信息。下面以例子进行简单的介绍。
请求成功:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise的另外请求方式</title>
</head>
<body>
<script>
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hello, YiBo!!!');
// reject('oh my god, you missed me');
})
}).then((res) => {
console.log(res);
}, (err) => {
console.log(err);
})
</script>
</body>
</html>
显示效果:
请求失败:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise的另外请求方式</title>
</head>
<body>
<script>
new Promise((resolve, reject) => {
setTimeout(() => {
// resolve('hello, YiBo!!!');
reject('oh my god, you missed me');
})
}).then((res) => {
console.log(res);
}, (err) => {
console.log(err);
})
</script>
</body>
</html>
显示效果:
4、Promise的链式调用
这里以一个例子展示Promise的链式调用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise链式调用</title>
</head>
<body>
<script>
/*
业务需求:发送网络请求,传输数据: one, 自己进行处理
处理完成后,在数据后面拼接:111, 然后自己处理数据
处理完成后,在数据后边拼接:222, 然后自己处理数据
*/
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('one');
}, 1000)
}).then((res) => {
console.log(res, '第一层处理10行代码');
return new Promise((resolve, reject) => {
resolve(res + '111');
})
}).then((res) => {
console.log(res, '第二层处理10行代码');
return new Promise((resolve, reject) => {
resolve(res + '222');
})
}).then((res) => {
console.log(res, '第三层处理10行代码');
})
</script>
</body>
</html>
在这个例子中,我们发现,每次数据的拼接都新 new了一个 Promise对象,但是在这个过程中,我们并没有异步请求。对于这种情况,我们可以不使用 new Promise来进行处理,可以直接使用 Promise.resolve() 来进行数据的处理。
代码展示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise链式调用</title>
</head>
<body>
<script>
/*
业务需求:发送网络请求,传输数据: one, 自己进行处理
处理完成后,在数据后面拼接:111, 然后自己处理数据
处理完成后,在数据后边拼接:222, 然后自己处理数据
*/
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('one');
}, 1000)
}).then((res) => {
console.log(res, '第一层处理10行代码');
return Promise.resolve(res + '111');
}).then((res) => {
console.log(res, '第二层处理10行代码');
return Promise.resolve(res + '222');
}).then((res) => {
console.log(res, '第三层处理10行代码');
})
</script>
</body>
</html>
显示效果:
虽然使用 Promise.resolve() 来进行数据拼接的操作已经比较简洁了,但是我们也可以直接return 来进行数据拼接操作。在进行return操作时,其实promise内部会帮我们进行一些包装,实际上也是以Promise.resolve的形式进行数据的拼接操作。
代码展示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise链式调用</title>
</head>
<body>
<script>
/*
业务需求:发送网络请求,传输数据: one, 自己进行处理
处理完成后,在数据后面拼接:111, 然后自己处理数据
处理完成后,在数据后边拼接:222, 然后自己处理数据
*/
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('one');
}, 1000)
}).then((res) => {
console.log(res, '第一层处理10行代码');
return res + '111';
}).then((res) => {
console.log(res, '第二层处理10行代码');
return res + '222';
}).then((res) => {
console.log(res, '第三层处理10行代码');
})
</script>
</body>
</html>
显示效果:
当我们发送数据失败时,会进入.catch() 处理后续的信息
代码展示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise链式调用</title>
</head>
<body>
<script>
/*
业务需求:发送网络请求,传输数据: one, 自己进行处理
处理完成后,在数据后面拼接:111, 然后自己处理数据
处理完成后,在数据后边拼接:222, 然后自己处理数据
*/
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('one');
}, 1000)
}).then((res) => {
console.log(res, '第一层处理10行代码');
return new Promise((resolve, reject) => {
resolve(res + '111');
})
}).then((res) => {
console.log(res, '第二层处理10行代码');
return new Promise((resolve, reject) => {
// resolve(res + '222');
reject('err!!! you are wrong!!!')
})
}).then((res) => {
console.log(res, '第三层处理10行代码');
}).catch((err) => {
console.log(err);
})
</script>
</body>
</html>
显示效果:
由于在这里也没有使用异步操作,所以也可以不用 new 一个Promise,可以使用***Promise.reject()***实现 reject()的操作。
代码展示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise链式调用</title>
</head>
<body>
<script>
/*
业务需求:发送网络请求,传输数据: one, 自己进行处理
处理完成后,在数据后面拼接:111, 然后自己处理数据
处理完成后,在数据后边拼接:222, 然后自己处理数据
*/
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('one');
}, 1000)
}).then((res) => {
console.log(res, '第一层处理10行代码');
return Promise.resolve(res + '111');
}).then((res) => {
console.log(res, '第二层处理10行代码');
return Promise.reject('err!!! you are wrong!!!');
}).then((res) => {
console.log(res, '第三层处理10行代码');
}).catch((err) => {
console.log(err);
})
</script>
</body>
</html>
显示效果:
除了使用 promise.reject(),也可以使用 throw来抛出错误信息
代码展示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise链式调用</title>
</head>
<body>
<script>
/*
业务需求:发送网络请求,传输数据: one, 自己进行处理
处理完成后,在数据后面拼接:111, 然后自己处理数据
处理完成后,在数据后边拼接:222, 然后自己处理数据
*/
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('one');
}, 1000)
}).then((res) => {
console.log(res, '第一层处理10行代码');
return Promise.resolve(res + '111');
}).then((res) => {
console.log(res, '第二层处理10行代码');
throw('err!!! you are wrong!!!');
}).then((res) => {
console.log(res, '第三层处理10行代码');
}).catch((err) => {
console.log(err);
})
</script>
</body>
</html>
显示效果:
5、Promise中all方法的使用
all方法需要使用的场景:
在实际项目开发过程中,我们可能需要同时接受多个请求,接受了多个请求之后才能够对数据进行处理,这个时候,我们可以使用Promise中的all方法,同时获取多个请求的数据。
Promise.all([]) //all中传递的是一个可迭代对象
代码展示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise中all方法的使用</title>
</head>
<body>
<script>
Promise.all([
new Promise((resolve, reject) => {
setTimeout(() => {
resolve({name: 'YiBo', age: 18});
}, 2000)
}),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve({name: '哈尔', age: 18});
}, 1000)
})
]).then(results => {
console.log(results[0]);
console.log(results[1]);
})
</script>
</body>
</html>
显示效果: