Promise与async/await都是Javascript的异步实现方案。
1.Promise
Promise 是ES6异步编程的一种解决方案,比传统的方案(回调函数和事件)更加的合理和强大。
快速掌握Promise,只需要记住以下特点:
Promise 执行基本流程如下图:

上面的定义听起似乎特别抽象,咱们举个生活中的栗子。
比如你中文要做饭,成功与否取决传入的布尔类型参数。使用Promise实现如下:
let cooking = (flag) => {
return new Promise((reslove, reject) => {
if (flag)
reslove('success')
reject('fail')
})
}
let p = cooking(true);
p.then(resp => {
console.log(resp)
}).catch(err => {
console.log(err)
})
参数为 true时输出 success,参数为false时,输出fail。
这个例子看似简单,但是我们必须要理解Promise本身是同步的,但是它的then方法和catch方法是异步的。比如,咱们做饭的时候是不是还可以听音乐,打扫家务,干些其它什么事情呢?
let cooking = (flag) => {
return new Promise((reslove, reject) => {
if (flag)
reslove('success')
reject('fail')
})
}
console.log('准备开始做饭了....')
let p = cooking(true);
p.then(resp => {
console.log(resp)
}).catch(err => {
console.log(err)
})
console.log('做饭的同时干些其它事情....')
输出结果为:
准备开始做饭了....
做饭的同时干些其它事情....
success
但是,这样还是显得不够真实,因为咱们做饭肯定一个比较费时的操作,通常我们在Promise里执行一些异步操作。程序改写如下:
let cooking = (flag) => {
return new Promise((reslove, reject) => {
setTimeout(()=>{
if (flag) {
reslove('success')
}
reject('fail')
},5000);
console.log('做饭无聊时,拍个抖音.....')
})
}
console.log('准备开始做饭了....')
let p = cooking(true);
p.then(resp => {
console.log(resp)
}).catch(err => {
console.log(err)
})
console.log('做饭的同时干些其它事情....')
输出结果:
准备开始做饭了....
做饭无聊时,拍个抖音.....
做饭的同时干些其它事情....
success
咱们把这里例子再扩展下,比如做完饭后,就开始吃饭,吃完饭后喝茶和洗澡。有些小伙伴想当然的改写如下:
let cooking = (flag) => {
return new Promise((reslove, reject) => {
setTimeout(()=>{
if (flag) {
reslove('success')
}
reject('fail')
},5000);
console.log('做饭无聊时,拍个抖音.....')
})
}
console.log('准备开始做饭了....')
let p = cooking(true);
p.then(resp => {
console.log(resp)
}).then(resp=>{
setTimeout(()=>{console.log('吃饭...')},5000)
}).then(resp=>{
setTimeout(()=>{console.log('喝茶...')},1000)
}).then(resp=>{
setTimeout(()=>{console.log('洗澡...')},3000)
}).catch(err => {
console.log(err)
})
console.log('做饭的同时干些其它事情....')
运行结果:
准备开始做饭了....
做饭无聊时,拍个抖音.....
做饭的同时干些其它事情....
success
喝茶...
洗澡...
吃饭...
结果变成了喝茶洗澡完了再吃饭,这就很尴尬了。出现这个错误的原因是他忽视了resolve返回的必须是另外一个Promise实例,否则后面三个setTimeout都是异步操作,并不如能保证线程的同步。
正确实现方式如下:
let cooking = (flag) => {
return new Promise((reslove, reject) => {
setTimeout(()=>{
if (flag) {
reslove('success')
}
reject('fail')
},5000);
console.log('做饭无聊时,拍个抖音.....')
})
}
console.log('准备开始做饭了....')
let p = cooking(true);
p.then(resp => {
console.log(resp)
if (resp === 'success') {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('吃饭...')
resolve('success')
}, 5000);
})
}
}).then(resp=>{
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('喝茶...')
resolve('success')
}, 1000);
})
}).then(resp=>{
return new Promise((reslove,reject)=>{
setTimeout(() => {
console.log('洗澡...')
reslove('success')
}, 3000);
})
}).catch(err => {
console.log(err)
})
console.log('做饭的同时干些其它事情....')
运行结果:
准备开始做饭了....
做饭无聊时,拍个抖音.....
做饭的同时干些其它事情....
success
吃饭...
喝茶...
洗澡...
有些小伙伴问:如果吃饭的时候发生些意外,是否会导致后面无法喝茶和洗澡呢?答案是肯定的。
代码改写如下:
let cooking = (flag) => {
return new Promise((reslove, reject) => {
setTimeout(()=>{
if (flag) {
reslove('success')
}
reject('fail')
},5000);
console.log('做饭无聊时,拍个抖音.....')
})
}
console.log('准备开始做饭了....')
let p = cooking(true);
p.then(resp => {
console.log(resp)
if (resp === 'success') {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('吃饭...')
reject('吃饭噎住了....')
}, 5000);
})
}
}).then(resp=>{
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('喝茶...')
resolve('success')
}, 1000);
})
}).then(resp=>{
return new Promise((reslove,reject)=>{
setTimeout(() => {
console.log('洗澡...')
reslove('success')
}, 3000);
})
}).catch(err => {
console.log(err)
})
console.log('做饭的同时干些其它事情....')
运行结果:
准备开始做饭了....
做饭无聊时,拍个抖音.....
做饭的同时干些其它事情....
success
吃饭...
吃饭噎住了....