前端萌新眼中的Promise及使用

一个 Promise 就是一个表明了异步操做最终完成或者失败的对象。这是MDN上关于Promise的解释。在前端开发中,Promise常常被拿来用于处理异步和回调的问题,来规避回调地狱和更好排布异步相关的代码。本篇文章对于Promise以及相关的async/await记录一些本身的理解和体会。前端

1、Promise的三种状态

从字面的意思理解,Promise便是承诺,既是承诺,那承诺的结果就会有成功和失败两种。并且,咱们许下承诺以后不会当即获得结果,在得到成功或是失败的结果以前,咱们还须要一点时间来履行这个承诺。Promise的构造其实像极了咱们生活中的承诺。ios

Promise

上面这张图就是Promise的结构图。就像咱们生活中的承诺同样,Promise也存在三种状态,一种是履行承诺的pending状态,一种是承诺失败时的Rejected状态,再就是承诺成功时Fullfilled状态。axios

接下来,咱们以爱情的名义来承诺一下:数组

let love = new Promise((resolve, reject) => {
    setTimeout(() => {         //开始谈恋爱,不过恋爱的结果要之后才知道
        let happy = Math.random() >= 0.3 ? true : false
        if ( happy ) {
            resolve('marry')    //恋爱成功,决定结婚
        } else {
            reject('break')     //恋爱失败,决定分手
        }    
    }, 500)
})


love.then(result => {
    console.log(result)   //处理恋爱成功的回调,result是上面resolve传过来的'marry'
}).catch(result => {
    console.log(result)   //处理恋爱失败的回调,result是上面reject传过来的'break'
})

复制代码

上面的代码就是一个简单却完整的Promise的例子。须要特别注意的是,Promise在通过pending状态达到成功或失败状态时就会凝固,即到达成功状态后不再会失败,失败之后也不会回到成功状态。浏览器

因此下面的Promise必定是失败状态的,即使reject后面跟了resolve也没用。正所谓:若爱,请深爱,若弃,请完全,不要暧昧,伤人伤己。柏拉图这话,说的就是Promise的状态凝固。bash

let love = new Promise((resolve, reject) => {
    reject('break')
    resolve('marry')
})

love.then(result => {
    console.log(result)
}).catch(result => {
    console.log(result)
})
复制代码

2、Promise的then与catch的几种写法

第一种,最多见的就是上面的写法, 使用then来捕捉resolve状态,使用catch来捕捉reject状态

love.then(result => {
    console.log(result)
}).catch(result => {
    console.log(result)
})

复制代码

第二种,不写catch, 把用来捕捉reject状态的函数也写到then里,可是效果和上面同样

love.then(result => {
    console.log(result)
}, result => {
    console.log(result)
})
复制代码

第三种,分开写,也是能够的

love.then(result => {     //只捕捉和处理成功状态
    console.log(result)
})

love.catch(result => {    //只捕捉和处理失败状态
    console.log(result)  
})
复制代码

3、快速构建一个成功或是失败状态的Promise

Promise自带了两种方法,咱们能够利用它们快速构建一个Promise,一个是Promise.resolve(), 用于构建成功状态的Promise;另外一个是Promise.reject(),用于构建失败状态的Promise。app

let p1 = Promise.resolve('success')
console.log(p1)   // 打出来的是 Promise {'success'}
p1.then(result => {
    console.log(result)  //打出来上面resolve传过来的字符串'success'
})

let p2 = Promise.reject('failed')   //上面是一个成功状态Promise,这是一失败状态的Promise
p2.catch(result => {
    console.log(result)
})

复制代码

4、使用Promise.all()来处理一类前端场景

在前端的开发实践中,咱们有时会遇到须要发送多个请求并根据请求顺序返回数据的需求,好比,咱们要发送a、b、c三个请求,这三个请求返回的数据分别为a一、a二、a3,而咱们想要a一、a二、a3按照咱们但愿的顺序返回。那么,使用Promise.all()方法能够完美的解决这一问题。dom

假设使用代码以下:异步

//模拟异步请求的函数
let request = (name, time) => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            let random = Math.random()
            if (random >= 0.2) {
                resolve(`${name}成功了`)
            } else {
                reject(`${name}失败了`)
            }
        }, time)    
    })
}

//构建三个Promise实例
let a = request('小明', 1000)
let b = request('小红', 500)
let c = request('小华', 1500)

//使用Promise.all(), 注意它接收的是一个数组做为参数 
Promise.all([b,a,c]).then(result => {
    console.log(result)
}).catch(result => {
    console.log(result)
})

复制代码

把上面的代码复制下来放到浏览器的调试控制台里多执行几回(第二次执行须要刷新)会发生什么事情呢?你可能猜到了:若是三个请求都成功的话,那么这三个请求所返回的数据就是按照发送请求的顺序排列的,即['小红成功了', '小明成功了', '小华成功了'],并且仍是以数组形式返回的;而当其中有请求失败了的话,就只会返回最早失败的结果。async

固然,除了这个场景之外,Promise.all()方法还能用于其它地方。好比说,一个页面上有两个请求,只有拿到了这两个请求的数据,页面才会展现,在这以前会显示一个loading加载图。使用Promise.all()也是能够很是简洁的解决这个问题。

5、Promise的链式调用

上面说过的then方法,在每次使用后依然会继续返回一个Promise对象。

let p = Promise.resolve('success')
let response = p.then(result => {
    console.log(result)
})
console.log(response)   //打出来的response是一个Promise对象
复制代码

由于then以后返回的仍是一个Promise对象,那咱们就能够继续then,只不事后面then拿到的参数是上一个then里return的内容,而这个return的内容既能够是普通的字符串、数字等(最后都会被封装成Promise)也能够是本身写的一个Promise对象。

接下来咱们接着上面爱的承诺继续写一个链式调用的例子:

let love = new Promise((resolve, reject) => {
    setTimeout(() => {
        let happy = Math.random() >= 0.3 ? true : false
        if ( happy ) {
            resolve('marry')
        } else {
            reject('break')
        }    
    }, 500)
})

let haveChild = new Promise((resolve, reject) => {
    setTimeout(() => {
       resolve('孩子生了!') 
    }, 1000)
})


love.then(result => {
    console.log(result)
    return haveChild  // 这里返回一个Promise对象,它的resolve会被下一个then捕捉
}).then(result => {
    console.log(result)
    return '最后,他们白头偕老!' //这里返回的字符串会传给下一个then
}).then(result => {
    console.log(result)
}).catch(error => { 
    console.log(error)
})

复制代码

这里须要注意的是,在链式调用的最必定要加上一个catch来捕捉链条中可能出现的错误!

6、Promise链式调用能够处理的一个业务场景

当咱们须要发送多个请求,然后一个请求老是依赖前一个请求的结果时,Promise的链式操做就能够派上用场了。

咱们使用axios来演示,axios自己就使用Promise进行封装,代码以下:

let request = (url) => {
    let result = axios.get(url)  //result是Promise对象
    result.then(response => {
        return response
    }).catch(error => {
        throw new Error('出错了!')
    })
}

request(url0).then(response => {
    return request(response.data.link)
}).then(result => {
    console.log(result)
}).catch(error => {
    console.log(error)
})

复制代码

上面的代码简单模拟了一下这个过程,有些地方还不完善。

以上就是我对Promise用法的一点理解,不少地方还不完善,若是出错,还请各位朋友们能及时指正!

这是我在掘金上的第一篇文章!感谢观看!

相关文章
相关标签/搜索