前言
Promise是一种处理异步操作的对象。
异步
- js是单线程执行的,一次只干一件事。
- 遇到需要耗时的代码,那就先挂起,先执行不耗时的代码,等到不耗时的代码执行完了,V8腾出手了,再执行耗时的代码。
function foo() {
console.log("foo");
}
function bar() {
console.log("bar");
}
foo();
bar();
打印结果
分析
bar()先被调用,先执行。
如果在foo中放入一个定时器,foo就会v8识别为耗时代码,后执行。
function foo() {
setTimeout(() => {
console.log("foo");
})
}
function bar() {
console.log("bar");
}
foo();
bar();
打印结果
如果一个函数b依赖另一个函数a的结果,但是a函数是一个耗时代码,会怎么执行?
let data = {}
function a() {
setTimeout(() => { // ajax
data = {name: 'lxp'}
}, 1000)
}
function b() {
console.log(data.name + '超级有钱');
}
a()
b()
打印结果
分析
由于a是耗时代码所以后执行,所以会先执行b,b打印的值为一个空对象的name,所以为undefined。
把b放到a里去调用
let data = null
function a() {
setTimeout(() => { // ajax
data = {name: 'lxp'}
b()
}, 1000)
}
function b() {
console.log(data.name + '超级有钱');
}
a()
打印结果
分析
这样我们就能拿到想要的结果,这样写也叫回调。
回调函数
将一个函数作为参数传给另一个函数,以便在某些事件发生时,被调用的函数能够在合适的时机执行传递过来的函数。回调函数能够处理异步操作。如果嵌套过深,一旦出现问题很难排查。
回调地狱
function a() {
b()
}
function b() {
c()
}
function c() {
d()
}
function d() {
e()
}
function e() {}
a()
Promise
能够把一个异步问题很好地执行为一个同步问题。
function eat() {
return new Promise((resolve, reject) => {
setTimeout(() =>{
console.log('吃饭')
resolve()
}, 2000)
})
}
function sleep() {
setTimeout(() =>{
console.log('睡觉')
}, 2000)
}
function learn() {
console.log('学习')
}
eat().then(() =>{
sleep()
learn()
})
打印结果
分析
eat()返回一个promise对象,这个函数在2s后通过调用resolve()函数来表明异步操作已完成,resolve()是promise内部提供的一个函数,resolve()执行成功后,.then()方法所包含的回调函数就会被调用。- 但由于
sleep()函数内部没有返回一个promise对象,所以v8引擎不会等待sleep()函数内的定时器执行完毕,直接执行后续learn()的代码。
如果改为:
function eat() {
return new Promise((resolve, reject) => {
setTimeout(() =>{
console.log('吃饭')
resolve()
}, 2000)
})
}
function sleep() {
return new Promise((resolve, reject) => {
setTimeout(() =>{
console.log('睡觉')
resolve()
}, 2000)
})
}
function learn() {
console.log('学习')
}
eat()
.then(() =>{
sleep()
})
.then(() =>{
learn()
})
打印结果
分析
由于第一个.then()没有任何返回值,所以无法确认是否要等到sleep()执行结束后再执行下一个.then(),所以不会等sleep()执行完毕就直接触发了下一个.then(),就先执行了learn()函数。
将sleep()返回给.then()
eat()
.then(() =>{
return sleep()
})
.then(() =>{
learn()
})
打印结果
reject-catch
定义一个a函数,内部放有一个定时器,在定时器内部放了一个reject()函数,传入err。定义一个函数b,只有当a执行完毕后才执行b,执行失败则返回err。
function a() {
return new Promise(function(resolve, reject){
setTimeout(function() {
console.log('a is ok');
reject('a')
}, 1000)
})
}
function b() {
console.log('b is ok');
}
// a().then(b())
a()
.then((res) => {
b()
})
.catch((err) => {
console.log(err)
})
执行结果
Promise.race
当需要处理多个异步操作时,若只需要最快执行的异步操作的结果时可以使用Promise.race。
function a() {
return new Promise(function(resolve, reject){
setTimeout(function() {
console.log('a is ok');
resolve('a')
}, 1000)
})
}
function b() {
return new Promise(function(resolve, reject){
setTimeout(function() {
console.log('b is ok');
resolve('b')
}, 500)
})
}
function c() {
console.log('c is ok');
}
Promise.race([a(), b()]).then(() =>{
c()
})
打印结果
Promise.all
用于执行多个异步操作时,当异步操作都成功完成后才执行其他操作。
Promise.all([a(), b()]).then(() =>{
c()
})
打印结果
总结
灵活运用Promise,能够更好地处理异步操作。