← 返回首页
Promise与async/await的区别(一)
发表时间:2022-08-22 11:30:22
Promise与async/await的区别

Promise与async/await都是Javascript的异步实现方案。

1.Promise

Promise 是ES6异步编程的一种解决方案,比传统的方案(回调函数和事件)更加的合理和强大。

快速掌握Promise,只需要记住以下特点:

  1. promise是一个js对象。
  2. promise对象的状态不受外界影响。promise有三种状态: pending(等待态),fulfiled(成功态),rejected(失败态);状态一旦改变,就不会再变。创造promise实例后,它会立即执行。
  3. promise对象的状态改变,只有两种可能:从pending变为resolved和从pending变为rejected。
  4. resolve返回的是另外一个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 
吃饭... 
吃饭噎住了....