promise
# 一、手写promise
参考文章:
Promise不会??看这里!!!史上最通俗易懂的Promise!!! (opens new window)
阮一峰大神文章:Promise对象 (opens new window)
面试官对不起!我终于会了Promise...(一面凉经泪目) (opens new window)
# 01.Promise特点
ECMAscript 6 原生提供了 Promise 对象。
Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息。
promise有三种状态: pending(等待态),fulfiled(成功态),rejected(失败态) ;
状态一旦改变,就不会再变。创造promise实例后,它会立即执行。
这个promise可以解决异步的问题,本身不能说promise是异步的
优点:
- 将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数,落入回调地狱;
- Promise 对象提供统一的接口,使得控制异步操作更加容易
缺点:
- 无法取消 Promise,一旦新建它就会立即执行,无法中途取消;
- 如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部;
- 当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
# 02.ES6 promise 用法详解
Promise是一个构造函数,本身有all、reject、resolve 常用方法,原型上有 then、catch 等方法。
Promise构造函数接收一个参数:函数,该函数需要传入两个参数:
- resolve: 异步操作执行成功后的回调函数;
- reject: 异步操作执行失败后的回调函数。
const p = new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('执行完成!');
resolve('异步操作成功啦!')
},2000);
})
2
3
4
5
6
# then链式操作
p.then((data) => {
console.log(data);
})
.then((data) => {
console.log(data);
})
.then((data) => {
console.log(data);
});
2
3
4
5
6
7
8
9
# reject用法
const p = new Promise((resolve,reject)=>{
setTimeout(function(){
const num = Math.ceil(Math.random()*10);
if(num<=5){
resolve(num);
}else{
reject('数字大于5')
}
},2000);
});
p.then((data)=>{
console.log('resolved',data);
},(err)=>{
console.log('rejected',err);
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
把Promise的状态置为rejected,这样我们在then中就能捕捉到,然后执行“失败”情况的回调。
then方法可以接受两个参数:
- 第一个对应resolve的回调;
- 第二个对应reject的回调,所以我们能够分别拿到他们传过来的数据。
# catch方法
catch其实它和then的第二个参数一样,用来指定reject的回调。
p.then((data)=>{
console.log('resolved',data)
}).catch((erro)=>{
console.log('rejected',erro);
})
2
3
4
5
此外,在执行resolve的回调(也就是上面then中的第一个参数)时,如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch方法中。
Promise 对象的错误具有"冒泡"性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个 catch 语句捕获。
# all方法
谁跑的慢,以谁为准执行回调。all接收一个数组参数,里面的值最终都算返回Promise对象。
Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。
const Promise1 = new Promise(function(resolve,reject){})
const Promise2 = new Promise(function(resolve,reject){})
const Promise3 = new Promise(function(resolve,reject){})
const p = Promise.all([Promise1,Promise2,Promise3])
p.then(function(){
//三个都成功则成功
},function(){
//只要有失败,则失败
})
2
3
4
5
6
7
8
9
10
11
有一个场景是很适合用这个的,一些游戏类的素材比较多的应用,打开网页时,预先加载需要用到的各种资源如图片、flash以及各种静态文件。所有的都加载完后,我们再进行页面的初始化。
# race方法
谁跑的快,以谁为准执行回调。
function requestImg(){
const p =new Promise((resolve,reject)=>{
const img = new Image();
img.onload = function(){
resolve(img);
}
img.src = 'path'
});
return p;
}
function timeout(){
const p = new Promise((resolve,reject)=>{
setTimeout(() => {
reject('图片请求超时');
}, 2000);
});
return p;
}
Promise.race([requestImg(),timeout()])
.then((data)=>{
console.log(data);
})
.catch((err)=>{
console.log(err);
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 03.手写Promise
封装一系列内置方法,需要包括:
- 捕获错误的方法 catch()
- 解析全部方法 all()
- 竞赛 race()
- 生成一个成功的 promise resolve()
- 生成一个失败的 promise reject()
# 二、闭包
# 三、原型
# 四、call apply
# 五、Webpack
参考文章:
🔥【万字】透过分析 webpack 面试题,构建 webpack5.x 知识体系 (opens new window)