一节课彻底弄懂promise、async、await(二)

作者 : 开心源码 本文共4553个字,预计阅读时间需要12分钟 发布时间: 2022-05-13 共208人阅读

上一篇呢,主要是聊了聊同步、异步,他们各自引申出来的‘执行栈’、‘消息队列’,以及‘宏任务’、‘微任务’,假如大家对这几个概念不太理解,可以去这个链接:

https://www.songma.com/p/61e7844e68d8

宏任务与微任务都是异步的,其中包括ajax请求、计时器等等,我们初步的理解一下promise,知道他是处理异步的一种方式,那么我们常用的一共有哪几种方法呢?

由于涉及的知识点比较多,这篇文章主要是讲一下,回调函数和promise:

一、回调函数

先上代码:function f2() {    console.log('2222')}function f1(callback){    console.log('111')  setTimeout(function () {    callback();   }, 5000);  console.log('3333')}f1(f2);先看下打印值是:1113333五秒后2222

相当于主线程执行完了,会通过回调函数去调用f2函数,这个没什么毛病。但是看下下面的例子:

现在我们读取一个文件,fileReader就是一个异步请求// 这个异步请求就是通过回调函数的方式获取的var reader = new FileReader()var file = input.files[0]reader.readAsText(file, 'utf-8',function(err, data){    if(err){        console.log(err)    } else {        console.log(data)    }})

现在看起来也很不错,但是假如文件上传出错了,我们还要在回调里面做判断,要是我们读取完这个文件接着要读取多个文件呢?是不是应该这么写:

读取完文件1之后再接着读取文件2、3var reader = new FileReader()var file = input.files[0]reader.readAsText(file1, 'utf-8',function(err1, data1){    if(err1){        console.log(err1)    } else {        console.log(data1)    }    reader.readAsText(file2, 'utf-8',function(err2, data2){        if(err2){            console.log(err2)        } else {            console.log(data2)        }        reader.readAsText(file3, 'utf-8',function(err3, data3){            if(err3){                console.log(err3)            } else {                console.log(data3)            }        })    })})

这么写可以实现需求,但是这个代码的可读性就比较差,看起来就不那么优雅,也就是我们常说的‘回调地狱’。那么怎样破解这种嵌套式的回调呢?ES6为我们提供了promise:

二、promise

首先我们从字面意思上了解一下什么是promise?promise可以翻译成承诺、保证,这个地方你可以了解为:

女朋友让我干了一件事,尽管还没干完,但是我保证这件事会有一个结果给你,成功(fulfiled)或者者失败(rejected),还有一个等待状态(pending)。

还是先上例子let promise = new Promise((resolve, reject) => {    setTimeout(() => {        resolve(2000) // 成功以后这个resolve会把成功的结果捕捉到        // reject(2000) // 失败以后这个reject会把失败的结果捕捉到    }, 1000)    console.log(1111)})promise.then(res => {    console.log(res) // then里面第一个参数就能拿到捕捉到的成功结果}, err =>{    console.log(res)// then里面第二个参数就能拿到捕捉到的失败结果})打印结果:11112000(一秒以后)
1、then链式操作

Promise对象的then方法返回一个新的Promise对象,因而可以通过链式调用then方法。

then方法接收两个函数作为参数,第一个参数是Promise执行成功时的回调,第二个参数是Promise执行失败时的回调,这个上面的例子说的很明白了,第二个参数捕捉的就是失败的回调。

两个函数只会有一个被调用,这句话怎样了解呢?
女朋友让你去做西红柿鸡蛋汤,你要么就去做,要么就不做,叫外卖,一定没有第三种选择。

函数的返回值将被用作创立then返回的Promise对象。这句话应该怎样了解呢?还是上例子:

let promise = new Promise((resolve, reject) => {    setTimeout(() => {        resolve(2000)    }, 1000)    console.log(1111)})promise.then(res => {    console.log(res) // 这个地方会打印捕捉到的2000    return res + 1000 // 这个函数的返回值,返回的就是这个promise对象捕捉到的成功的值}).then(res => {    console.log(res) //这个地方打印的就是上一个promise对象return的值})所以打印顺序应该是:111120003000

刚才我们看到了then接受两个参数,一个是成功的回调、一个是失败的回调,看起来如同也不是那么优雅,promise里除了then还提供了catch方法:

2、catch捕捉操作

这个catch就是专门捕捉错误的回调的,还是先看例子:

let promise = new Promise((resolve, reject) => {    setTimeout(() => {        reject(2000) // 失败以后这个reject会把失败的结果捕捉到    }, 1000)    console.log(1111)})promise.catch(res => {    console.log(res) // catch里面就能拿到捕捉到的失败结果})打印结果:11112000(一秒以后)

除了then和catch之外,promise还有两个语法,all和race,我们也简单用一下:

3、all

现在我们有这么一个需求,一共有三个接口A、B、C,必需三个接口都成功以后,才能发起第四个请求,怎样实现呢?

链式调用
let getInfoA = new Promise((resolve, reject) => {    console.log('小A开始执行了')    resolve()}).then(res => {    let getInfoB = new Promise((resolve, reject) => {        console.log('小B开始执行了')        resolve()    }).then(res => {        let getInfoC = new Promise((resolve, reject) => {            console.log('小C开始执行了')            resolve()        }).then(res => {            console.log('全都执行完了!')        })    })})

一层套一层的,如同不是那么优雅

all
let getInfoA = new Promise((resolve, reject) => {    console.log('小A开始执行了')    resolve()})let getInfoB = new Promise((resolve, reject) => {    console.log('小B开始执行了')    resolve()})let getInfoC = new Promise((resolve, reject) => {    console.log('小C开始执行了')    resolve()})Promise.all([getInfoA, getInfoB, getInfoC]).then(res => {   console.log('全都执行完了!')})

接收一个Promise对象组成的数组作为参数,当这个数组所有的Promise对象状态都变成resolved或者者rejected的时候,它才会去调用then方法。非常完美,非常优雅。

4、race

现在又有一个需求,同样是接口A、B、C,只需有一个响应了,我即可以调接口D,那么怎样实现呢?

1、传统方式

let getInfoA = new Promise((resolve, reject) => {    console.log('小A开始执行了')    setTimeout((err => {        resolve('小A最快')    }),1000)}).then(res =>{    console.log(res)})let getInfoB = new Promise((resolve, reject) => {    console.log('小B开始执行了')    setTimeout((err => {        resolve('小B最快')    }),1001)}).then(res =>{    console.log(res)})let getInfoC = new Promise((resolve, reject) => {    console.log('小C开始执行了')    setTimeout((err => {        resolve('小C最快')    }),1002)}).then(res =>{    console.log(res)})打印结果小A开始执行了小B开始执行了小C开始执行了小A最快

这个方法得写三遍,如同也不是那么优雅,一起来看下race应该怎样写?

2、race

let getInfoA = new Promise((resolve, reject) => {    console.log('小A开始执行了')    setTimeout((err => {        resolve('小A最快')    }),1000)})let getInfoB = new Promise((resolve, reject) => {    console.log('小B开始执行了')    setTimeout((err => {        resolve('小B最快')    }),1001)})let getInfoC = new Promise((resolve, reject) => {    console.log('小C开始执行了')    setTimeout((err => {        resolve('小C最快')    }),1002)})Promise.race([getInfoA, getInfoB, getInfoC]).then(res => {    console.log(res)})打印结果小A开始执行了小B开始执行了小C开始执行了小A最快

与Promise.all类似的是,Promise.race都是以一个Promise对象组成的数组作为参数,不同的是,只需当数组中的其中一个Promsie状态变成resolved或者者rejected时,即可以调用.then方法了。

promise是ES6用来处理异步的一个方法,现在用的已经比较广泛了,像我们经常用的axios,他就是用promise封装的,用起来非常方便。

除了promise,ES6还为我们提供了终极大招async、await,由于这两个知识块比较大,所以我们准备下一篇文章讲。

个人的微信公众号:小Jerry有话说,平常会发少量技术文章和读书笔记,欢迎交流。

微信图片_20200325182734.jpg

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 一节课彻底弄懂promise、async、await(二)

发表回复