ES6的Promise对象和async函数

92 阅读8分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路。

Promise对象

Promise是一个对象,从它可获取异步操作的一些信息。

基本的知识在菜鸟教程中可学习:www.runoob.com/w3cnote/es6…

通过new Promise() 即可构造一个Promise实例,这个构造函数接收一个函数,函数接收两个参数:resolve和reject,代表改变实例的状态到已完成(resolve)或已拒绝(reject)。

相关API

这里定义fn1和fn2,简单介绍了API的使用。

const fn1 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        let num = 'fn1';
        // 内部定义成功时调用
        resolve(num);
        // 内部定义失败时调用
        reject('err-fn1');
    },200)
})

const fn2 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        // 内部定义成功时调用
        resolve('fn2');
        // 内部定义失败时调用
        reject('err-fn2');
    },100)
})

fn1.then((res1)=>{
    console.log(res1);
},(err1)=>{
    console.log(err1)
})

fn2.then((res2)=>{
    console.log(res2);
},(err2)=>{
    console.log(err2);
})

Promise构造函数

Promise(excutor){}

1.excutor函数:执行器(resolve,reject)=>{}

2.resolve函数:内部定义成功时我们调用的函数 (value)=>{}

3.reject函数:内部定义失败时我们调用的函数 (reason)=>{}

Promise.prototype.then方法

(onResolved,onRejected)

1.onResolve函数:成功的回调函数 (value)=>{}

2.onReject函数:失败的回调函数 (reason)=>{}

指定用于得到成功value的成功回调和用于得到失败reason的失败回调,返回一个新的Promise对象。

Promise.prototype.catch方法

(onReject)

1.onReject函数:失败的回调函数 (reason)=>{}

catch为then的语法糖,相当于:then(undefined,onRejected)

then和catch属于Promise实例对象。

Promise.prototype.finally()

finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。

Promise方法

这里面的方法属于Promise函数对象的。

Promise.resolve

Promise.resolve方法:(value)=>{}

value 成功的数据或Promise对象

Promise.resolve返回一个成功或失败的Promise对象。

作用:快速得到一个Promise对象,可以封装一个值,将值转化为一个promise对象。

Promise.resolve将值转换为Promise对象:

let fn = Promise.resolve(999);
console.log(fn);

image.png

若传入的参数为非Promise对象的值,则返回结果为成功Promise对象。 若传入的参数为Promise对象,则参数的结果决定resolve的结果。

参数Promise对象成功:

// 若传入的参数为非Promise对象的值,则返回结果为成功Promise对象。
// 若传入的参数为Promise对象,则参数的结果决定resolve的结果。
let fn = Promise.resolve(new Promise((resolve,reject)=>{
    // 参数成功的结果
    resolve('success');
    console.log(resolve,reject);
}));
console.log(fn);

image.png

参数Promise对象失败:

// 若传入的参数为非Promise对象的值,则返回结果为成功Promise对象。
// 若传入的参数为Promise对象,则参数的结果决定resolve的结果。
let fn = Promise.resolve(new Promise((resolve,reject)=>{
    // 参数成功的结果
    reject('err');
    console.log(resolve,reject);
}));
console.log(fn);

fn.catch((err)=>{
    console.log(err);
})

image.png

Promise.reject

Promise.reject 方法:(reson)=>{}

reson 失败的原因

Promise.reject返回一个失败的Promise对象。

Promise.reject将值转换为Promise对象:

let fn = Promise.reject(999);
console.log(fn);

fn.catch((err)=>{
    console.log(err);
})

image.png

不管传入的参数为非Promise对象还是Promise对象,则返回结果都为失败的Promise对象。

参数Promise对象成功:

let fn = Promise.reject(new Promise((resolve,reject)=>{
    // 参数成功的结果,但是Promise.reject依旧返回失败的Promise对象。
    resolve('success');
    console.log(resolve,reject);
}));
console.log(fn);

fn.catch((err)=>{
    console.log(err);
})

返回结果是失败的Promise对象:

image.png

参数Promise对象失败:

let fn = Promise.reject(new Promise((resolve,reject)=>{
    // 参数失败的结果,Promise.reject依旧返回失败的Promise对象。
    reject('err');
    console.log(resolve,reject);
}));
console.log(fn);

fn.catch((err)=>{
    console.log(err);
})

返回结果是失败的Promise对象:

image.png

Promise.all

Promise.all方法:(promises)=>{}

promises:包含n个Promise的数组

返回一个新的Promise,只有所有的Promise成功才成功,只要有一个失败了就直接失败。

成功的结果是每一个Promise对象成功结果组成的数组,失败的结果为失败的Promise对象失败的结果。

全部成功

let fn = new Promise((resolve,reject)=>{
    resolve('success');
    console.log(resolve,reject);
});
let fn1 = Promise.resolve('success-1');
let fn2 = Promise.resolve('success-2');
const result = Promise.all([fn,fn1,fn2])
console.log(result);

image.png

失败一个:

let fn = new Promise((resolve,reject)=>{
    resolve('success');
    console.log(resolve,reject);
});
let fn1 = Promise.resolve('success-1');
let fn2 = Promise.reject('err');
const result = Promise.all([fn,fn1,fn2])
console.log(result);

result.catch((err)=>{
    console.log(err);
})

image.png

失败多个,只返回第一个错误的信息:

let fn = new Promise((resolve,reject)=>{
    resolve('success');
    console.log(resolve,reject);
});
let fn1 = Promise.reject('err-1');
let fn2 = Promise.reject('err-2');
const result = Promise.all([fn,fn1,fn2])
console.log(result);

result.catch((err)=>{
    console.log(err);
})

image.png

Promise.race

Promise.race方法:(promises)=>{}

promises:包含n个Promise的数组

返回一个新的Promise,第一个完成的promise的结果状态就是最终的结果状态。

let fn = new Promise((resolve,reject)=>{
    resolve('success');
    console.log(resolve,reject);
});
let fn1 = Promise.reject('err-1');
let fn2 = Promise.reject('err-2');
const result = Promise.race([fn,fn1,fn2])

console.log(result);

image.png

let fn = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve('success');
        console.log(resolve,reject);
    },100)
});
let fn1 = Promise.resolve('success-1');
let fn2 = Promise.resolve('success-2');
const result = Promise.race([fn,fn1,fn2])

console.log(result);

image.png

改变Promise对象状态的方式

改变Promise对象状态有三种方式:1.resolve 函数。2.reject 函数。3.抛出错误。

// 改变Promise对象状态的方式
let fn = new Promise((resolve,reject)=>{
    console.log(resolve,reject);
    // 1.resolve 函数  pending => fulfilled(resolved)
    resolve('success'); 

    // 2.reject 函数  pending => rejected
    reject('err');

    // 3.抛出错误 pending => rejected
    throw('抛出错误');
});

改变Promise对象状态和指定回调先后顺序

1.谁先谁后都有可能,正常情况下是先指定回调再改变状态,但也可以先改变状态再指定回调。

如何先改变状态再指定回调

1.在执行器中的是一个同步任务。

2.在执行器中直接调用resolve()和reject()。

3.延迟更长时间才调用then。

得到数据:

1.如果先指定回调,那么当状态发生变化时,回调函数就会调用,得到数据。

2.如果先改变状态,那么当指定回调时,回调函数就会调用,得到数据。

then方法的返回结果

由then方法里面指定回调函数的返回值决定then方法的返回结果。

// then方法的返回结果
        let fn = new Promise((resolve,reject)=>{
            console.log(resolve,reject);
            resolve('success'); 
        });

        const result = fn.then((res)=>{
            console.log(res);
            // // 1.抛出错误,此时then返回一个Promise对象,状态为rejected。
            // throw '抛出错误';
            // 2.返回结果为一个非Promise对象,此时then返回一个Promise对象,状态为fulfilled(resolved)。
            // return 999;
            // 3.返回结果为一个Promise对象,此时then返回一个Promise对象,return返回的Promise对象的状态决定then返回Promise对象的状态。
            return new Promise((resolve,reject)=>{
                console.log(resolve,reject);
                resolve('success');
                // reject('err');
            })
        },(err)=>{
            console.log(err);
        })
        
        console.log(result);

Promise链式调用-串联多个任务

原理就是then方法的返回结果也是一个Promise对象,该Promise对象也有then方法。

// Promise串联多个任务
        let fn = new Promise((resolve,reject)=>{
            console.log(resolve,reject);
            setTimeout(()=>{
                resolve('success');
            })
        });

        fn.then((res)=>{
            // 这里调用的原因是上面Promise对象resolve('success')返回为成功的。
            console.log(res); // success
            return new Promise((resolve,reject)=>{
                console.log(resolve,reject);
                resolve('success-1');
            })
        }).then((res)=>{
            // 这里调用的原因是上面Promise对象 resolve('success-1')返回为成功的。
            console.log(res); // success-1
        }).then((res)=>{
            // 这里返回undefined原因是上层没有返回值,所以为undefined。
            console.log(res); // undefined
        })

Promise异常穿透

当使用Promise的then链式调用时,可以在最后指定失败的回调。前面任何操作出现了异常,都会传到最后失败的回调中处理。

// Promise串联多个任务
let fn = new Promise((resolve,reject)=>{
    console.log(resolve,reject);
    setTimeout(()=>{
        resolve('success');
    })
});

fn.then((res)=>{
    console.log(res); // success
    return new Promise((resolve,reject)=>{
        console.log(resolve,reject);
        // resolve('success-1');
        reject('err')
    })
}).then((res)=>{
    console.log(res); // success-1
}).then((res)=>{
    console.log(res); // undefined
}).catch((err)=>{
    // 前面任何一层出现异常,都会传到该回调函数中处理。
    console.log(err);
})

image.png

中断Promise链

当使用Promise的then链式调用时,在中间中断,不再调用后面的回调函数。中断方法:在回调函数中返回一个pendding状态的Promise对象。

没中断前:

// Promise串联多个任务
let fn = new Promise((resolve,reject)=>{
    console.log(resolve,reject);
    setTimeout(()=>{
        resolve('success');
    })
});

fn.then((res)=>{
    console.log(res); // success
}).then((res)=>{
    console.log(res); // success-1
}).then((res)=>{
    console.log(res); // undefined
}).catch((err)=>{
    // 前面任何一层出现异常,都会传到该回调函数中处理。
    console.log(err);
})

image.png

中断后:

// Promise串联多个任务
let fn = new Promise((resolve,reject)=>{
    console.log(resolve,reject);
    setTimeout(()=>{
        resolve('success');
    })
});

fn.then((res)=>{
    console.log(res); // success
    // 加一个pendding
    return new Promise(()=>{})
}).then((res)=>{
    console.log(res); // success-1
}).then((res)=>{
    console.log(res); // undefined
}).catch((err)=>{
    // 前面任何一层出现异常,都会传到该回调函数中处理。
    console.log(err);
})

image.png

async

使用Promise实现

const fn = ()=>{
            return new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    console.log(resolve,reject);
                    resolve('fn');
                },200)
            })
        }

        const fn1 = ()=>{
            return new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    console.log(resolve,reject);
                    resolve('fn1');
                },1000)
            })
        }

        const fn2 = ()=>{
            return new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    console.log(resolve,reject);
                    resolve('fn2');
                },100)
            })
        }

        fn().then((res)=>{
            console.log(res);
        });

        fn1().then((res)=>{
            console.log(res);
        });

        fn2().then((res)=>{
            console.log(res);
        });

image.png

现在实现的顺序想为:fn->fn1->fn2

const fn = ()=>{
            return new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    console.log(resolve,reject);
                    resolve('fn');
                },200)
            })
        }

        const fn1 = ()=>{
            return new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    console.log(resolve,reject);
                    resolve('fn1');
                },1000)
            })
        }

        const fn2 = ()=>{
            return new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    console.log(resolve,reject);
                    resolve('fn2');
                },100)
            })
        }

        fn().then((res)=>{
            console.log(res);
            fn1().then((res)=>{
                console.log(res);
                fn2().then((res)=>{
                    console.log(res);
                })
            })
        })

image.png

这样就会一层一层的调用很多,使用async函数能够解决该问题。

基本介绍在这里:www.runoob.com/w3cnote/es6…

使用async函数可以解决上面问题:

const fn = ()=>{
            return new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    console.log(resolve,reject);
                    resolve('fn');
                },200)
            })
        }

        const fn1 = ()=>{
            return new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    console.log(resolve,reject);
                    resolve('fn1');
                },1000)
            })
        }

        const fn2 = ()=>{
            return new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    console.log(resolve,reject);
                    resolve('fn2');
                },100)
            })
        }

        const fnA = async ()=>{
            const fnAwait = await fn(); // 等fn()执行完再往下执行
            const fn1Await = await fn1(); // 等fn1()执行完再往下执行
            const fn2Await = await fn2(); // 等fn2()执行完再往下执行

            console.log(fnAwait);
            console.log(fn1Await);
            console.log(fn2Await);
        }

        fnA();

image.png

其中,await操作符用于等待一个Promise对象或非Promise对象,它只能在异步函数async function内部使用。

如果它等到的不是一个Promise对象,那await表达式的运算结果就是它等的值。

如果它等到的是一个Promise对象,await就忙起来了,它会阻塞后面的代码,等着Promise 对象resolve,然后将得到resolve的值作为await表达式的运算结果。

然后恢复async函数的执行并返回解析值。