1.Promise是什么
- 认识Promise
Promise是异步操作的一种方式
回调函数
document.addEventListener('click', () => {
console.log('这是异步请求!');
}, false);
console.log('这是同步请求!');
- 什么时候使用Promise
Promise一般用来解决层层嵌套的回调函数(回调地域 callback hell)的问题
* {
padding: 0;
margin: 0;
}
#box {
width: 180px;
height: 180px;
background-color: aquamarine;
transition: all .5s;
}
<div id="box"></div>
const move = (el, {
x = 0,
y = 0
} = {}, end = () => {}) => {
el.style.transform = `translate3d(${x}px, ${y}px, 0)`;
el.addEventListener(
'transitionend',
() => {
end();
}, false
);
};
const boxEl = document.getElementById('box');
const movePromise = (el, point) => {
return new Promise(resolve => {
move(el, point, () => {
resolve();
});
});
}
document.addEventListener('click', () => {
movePromise(boxEl, {
x: 150
}).then(() => {
return movePromise(boxEl, {
x: 150,
y: 150
})
}).then(() => {
return movePromise(boxEl, {
y: 150
})
}).then(() => {
return movePromise(boxEl, {
x: 0,
y: 0
})
})
});
//promise
const boxEl = document.getElementById('box');
document.addEventListener('click', () => {
move(boxEl, {
x: 150
}, () => {
move(boxEl, {
x: 150,
y: 150
}, () => {
move(boxEl, {
y: 150
}, () => {
move(boxEl, {
x: 0,
y: 0
});
})
})
})
})
2.Promise的使用
- 实例化构造函数生成实例对象
Promise解决的不是回调函数,而是回调地狱
console.log(Promise); //ƒ Promise() { [native code] }
const p = new Promise(() => {});
- Promise的状态
Promise有3种状态, 一开始是pending( 未完成), 执行( reject), 变成fulfilled( resolved), 已成功
Promise的状态一旦改变,就不会再改变了
const p = new Promise((resolve, reject) => {
resolve(); //then -- success
// 执行resolve,变成rejected,已失败
pending - > fulfilled
reject(); //then -- error
pending - > reject
});
console.log(p);
//Promise {<pending>} 等待状态
//Promise {<fulfilled>: undefined} 成功
//Uncaught (in promise) undefined失败
- then方法
p.then(() => {
console.log('success');
}, () => {
console.log('error');
})
- resolve和reject函数的参数
const p = new Promise((resolve, reject) => {
// resolve({
// username: 'zhangsan'
// });
reject(new Error('err!'));
});
p.then((data) => {
console.log('success', data); //success {username: "zhangsan"}
}, (data) => {
console.log('error', data); //error Error: err!
})
3.then()
- 什么时候执行
pending->fulfilled时,执行then的第一个回调函数
pending->rejected时,执行then的第二个回调函数 - 执行后的返回值
const p = new Promise((resolve, reject) => {
resolve();
// reject();
});
const p2 = p.then( () => {}, () => {} ).then.then;
console.log(p, p2, p === p2);
//Promise {<fulfilled>: undefined} undefined false
- then方法返回的Promise对象的状态改变
const p = new Promise((resolve, reject) => {
// resolve();
reject();
});
p.then(
() => {
console.log('success');
}, () => {
console.log('err!');
//在then的回调函数中,return后面的东西,会用Promise包装一下
return 123
// 等价于
// return new Promise(resolve => {
// resolve(123);
// })
//默认返回的永远是成功状态的Promise对象
// return new Promise((resolve, reject) => {
// reject('reason');//222err! reason
// })
}
).then(
(data) => {
console.log('success222', data);
return new Promise((resolve, reject) => {
resolve('then - 123');
})
}, (err) => {
console.log('222err!', err);
}
).then(
(data) => {
console.log('success333', data);
}, (err) => {
console.log('333err!', err);
}
);
4.catch()
- 有什么用
then(
data => {},
err => {}
);
then(data => {});
catch专门用来处理reject状态
catch本质上是then的特例
then(null, err => {});
- 基本用法
new Promise((resolve, reject) => {
// resolve(123);
reject('error!');
}).then(data => {
console.log(data); //123
})
// .then(null, err => {
// console.log(err); //error!
// })
.catch(err => {
console.log(err); //error!
throw new Error('error!');
}).then(data => {
console.log(data); //undefined
}).catch(err => {
console.log(err); //Error: error! at 62-catch().html:37
})
catch() 可以捕获它前面的错误
一般总是建议, Promise对象后面跟catch方法, 这样可以处理Promise内部发生的错误
5.finally()
- 什么时候执行
当Promise状态发生改变时,不论如何变化都会执行,不变化不执行
new Promise((resolve, reject) => {
// resolve(123);
reject('123');
}).finally(data => {
console.log(data);
}).catch(data => {
console.log(data);
})
- 本质
finally()本质上是then()的特例
new Promise((resolve, reject) => {
// resolve(123);
reject('err');
}).finally(data => {
console.log(data);
}).catch(err => {})
//等同于
new Promise((resolve, reject) => {
// resolve();
reject('err!');
}).then(result => {
return result;
}, err => {
return new Promise((resolve, reject) => {
reject(err);
});
}).then(data => {
console.log(data);
}).catch(err => {
console.log(err);
});
6.Promise.resolve和Promise.reject
- Promise.resolve();
是成功状态Promise的一种简写
new Promise(resolve => resolve('success'));
//简写
Promise.resolve('foo');
参数
一般参数
Promise.resolve('foo').then(data => {
console.log(data); //foo
})
Promise
当Promise.resolve()接收的是Promise对象时,直接返回这个Promise对象,什么都不做
const p1 = new Promise(resolve => {
setTimeout(resolve, 1000, '执行了!');
// setTimeout(() => {
// resolve('执行了!');
// }, 1000)
});
Promise.resolve(p1).then(data => {
console.log(data); //执行了!
});
等价于
p1.then(data => {
console.log(data); //执行了!
})
console.log(Promise.resolve(p1) === p1); //true
当resolve函数接收的是Promise对象时,后面then会根据传递的Promise对象的状态变化决定执行哪一个回调
new Promise(resolve => resolve(p1)).then(data => {
console.log(data); //执行了!
})
具有than方法的对象
const thenable = {
then(resolve, reject) {
// console.log('then');//then
resolve('data');
// reject('data');
}
};
Promise.resolve().then(
data => console.log(data), //undefined
err => console.log(err),
);
console.log(Promise.resolve(thenable));
//Promise {<pending>};
- Promise.reject()
失败状态Promise的一种简写形式
new Promise((resolve, reject) => {
reject('error!');
}).catch(err => console.log(err));
等价于
Promise.reject('error!');
参数
不管什么参数,都会原地不动的向后传递,作为后续方法的参数
const p1 = new Promise(resolve => {
setTimeout(resolve, 1000, '执行了!');
});
Promise.reject(p1).catch(err => console.log(err));
//Promise {<pending>}
new Promise((resolve, reject) => {
resolve(123);
}).then(data => {
// return data;
return Promise.reject('error!!');
}).then(data => console.log(data)) //123
.catch(err => console.log(err)); //error!
7.Promise.all()
- 有什么用
Promise.all() 关注多个Promise对象的状态变化
传入多个Promise实例,包装成一个新的Promise实例返回 - 基本用法
const delay = ms => {
return new Promise(resolve => {
setTimeout(resolve, ms);
})
}
const p1 = delay(1000).then(() => {
console.log('p1 完成了!');
return 'p111';
})
const p2 = delay(2000).then(() => {
console.log('p2 完成了!');
// return 'p222';
return Promise.reject('error!!');
})
Promise.all()的状态变化与所有传入的Promise实例对象有关
所有状态都变成resolved,最终状态才会变成resolved
只要有一个变成rejected, 最终的状态就变成rejected
const p = Promise.all([p1, p2]);
p.then(data => {
console.log(data);
}, err => {
console.log(err);
});
8.Promise.race()和Promise.allSettled()
const delay = ms => {
return new Promise(resolve => {
setTimeout(resolve, ms);
})
}
const p1 = delay(1000).then(() => {
console.log('p1 完成了!');
return 'p111';
})
const p2 = delay(2000).then(() => {
console.log('p2 完成了!');
// return 'p222';
return Promise.reject('error!!');
});
- Promise.race()
Promise.race()的状态取决于第一个完成的Promise实例对象,
如果第一个失败的成功了,那最终的就成功;
如果第一个完成的失败了,那最终的就失败
const racePromise = Promise.race([p1, p2]);
racePromise.then(data => {
console.log(data);
}, err => {
console.log(err);
});
- Promise.allSettled()
Promise.allSettled()的状态与传入的Promise状态无关
永远都是成功的
它会忠实的记录下各个Promise的表现
const allSettledPromise = Promise.allSettled([p1, p2]);
allSettledPromise.then(data => {
console.log('success', data);
});
9.Promise()注意事项
- resolve或reject函数执行后的代码
推荐调用resolve或reject函数的时候加上return,不再执行它们后面的代码
new Promise((resolve, reject) => {
return resolve(123);
// return reject('error!');
console.log('hi');
});
- Promise.all/race/allSettled的参数问题
参数如果不是Promise数组,会将不是Promise的数组元素转变成Promise对象
Promise.all([1, 2, 3]).then(datas => {
console.log(datas);
});
// 等价于
Promise.all([Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3)]).then(datas => {
console.log(datas);
})
不只是数组,任何可遍历的都可以作为参数
数组,字符串,Set,Map、Nodelist、arguments
Promise.all(new Set([1, 2, 3])).then(datas => {
console.log(datas);
})
- Promise.all/race/allSetted的错误处理
const delay = ms => {
return new Promise(resolve => {
setTimeout(resolve, ms);
})
}
const p1 = delay(1000).then(() => {
console.log('p1 完成了!');
// return 'p111';
return Promise.reject('111error!!');
});
// 单独处理
// .catch(err => {
// console.log(err);
// });
const p2 = delay(2000).then(() => {
console.log('p2 完成了!');
// return 'p222';
// return Promise.reject('222error!!');
});
const allPromise = Promise.all([p1, p2]).then(datas => {
console.log(datas);
}).catch(err => {
console.log(err); //统一处理
})
错误既可以被单独处理。也可以统一处理
一旦被处理,就不会在其他地方再处理一遍。
10.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>Promise()的应用</title>
</head>
<body>
<img src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fcdn.duitang.com%2Fuploads%2Fitem%2F201410%2F20%2F20141020162058_UrMNe.jpeg&refer=http%3A%2F%2Fcdn.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1620724097&t=e48d8f05d643c62ec5042ce874da5aa4"
alt="樱桃小丸子" srcset="" id="img">
<script>
// 异步加载图片
const loadImgAsync = url => {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => {
resolve(img);
};
img.onerror = () => {
reject(`Coult not load images at ${url}`);
};
img.src = url;
});
}
const imgDOM = document.getElementById('img');
loadImgAsync('https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fcdn.duitang.com%2Fuploads%2Fitem%2F201408%2F19%2F20140819011654_ThLAM.thumb.700_0.png&refer=http%3A%2F%2Fcdn.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1620725034&t=29106a44810fa83ad0fdfaa9c8dfc0b5').then(
img => {
console.log(img.src);
setTimeout(() => {
imgDOM.src = img.src;
}, 2000)
}
).catch(err => {
console.log(err);
});
</script>
</body>
</html>
11.小结
- Promise 是什么
Promise 是异步操作的一种解决方案
Promise 一般用来解决层层嵌套的回调函数的问题
Promise 解决的不是回调函数,而是回调地狱 - Promise 的状态
Promise 有 3 种状态
pending(未完成)
resolved/fulfilled(已成功)
rejected(已失败)
状态一旦变化,就不会再改变了 - Promise 的基本用法
推荐在调用 resolve 或 reject 函数的时候加上 return - then()
pending->resolved 时,执行 then 的第一个回调函数
pending->rejected 时,执行 then 的第二个回调函数
状态不改变,then() 的回调函数都不会被执行
then() 执行后返回一个新的 Promise 对象
可以通过 return 语句改变返回的 Promise对象的状态
then() 可以向后传值
- catch()
catch 专门用来处理 rejected 状态
catch 本质上是 then 的特例
建议 Promise 对象后面要跟 catch 方法,这样可以处理 Promise
内部发生的错误 - finally()
当 Promise 状态发生变化时,不论如何变化都会执行
finally() 本质上是 then() 的特例 - Promise.resolve() 的本质
成功状态 Promise 的一种简写形式
- Promise.resolve() 的参数
参数是 Promise 实例对象时,直接返回这个 Promise 对象
参数是具有 then 方法的对象时,会立即执行它的 then 方法
- Promise.resolve() 的参数
参数是其他值时,相当于通过 resolve 函数传参 - Promise.reject()
失败状态 Promise 的一种简写形式
不管什么参数,都会原封不动地向后传递,作为后续方法的参数 - Promise.all/race/allSettled()
只要是可遍历的,都可作为参数
参数的“集合”中若有成员不是 Promise 对象,内部会将其转变成 Promise 对象
返回一个新的 Promise 实例对象
错误既可以单独处理,也可以统一处理 - Promise.all()
所有状态都变成 resolved,最终的状态才会变成 resolved
只要有一个变成 rejected,最终的状态就变成 rejected - Promise.race()
最终的状态取决于第一个完成的 Promise 实例对象
如果第一个完成的成功了,那最终的就成功
如果第一个完成的失败了,那最终的就失败 - Promise.allSettled()
最终的状态永远都是成功的,与传入的 Promise 对象状态无关
会记录下各个 Promise 的表现