Javascipt 中,当我们需要处理类似网络请求这样的 异步事件 时,如果代码出现多层嵌套关系,就会使网络请求变得非常复杂,甚至产生回调地狱,而 ES6 对此提供了一种更优雅的解决异步编程的方式,那就是 —— “ Promise ”。

如何使用?

突然某天我们有如下需求:

向服务器发送网络请求,服务器返回一个 data 对象,这个 data 对象中包含下一个网络请求的 url,第二次请求再次返回 data 对象,拿到第三次请求的 url

上述需求存在多层嵌套关系,我们用 Ajax 可以这样实现:

$.ajax({
    url: 'url_1',
    success(data) {
        var url_2 = data.url
        $.ajax({
            url: 'url_2',
            success(data) {
                var url_3 = data.url
                $.ajax({
                    url: 'url_2',
                    success(data) {
                        console.log(data)
                    }
                })
            }
        })
    }
})

虽然达到了目的,但是这样的代码看起来就非常混乱,当我们改变需求或者需要嵌套更多的请求时,会变得异常麻烦。

接下来我们试着用 Promise 来对上面的代码做些改动:

/* new 一个 Promise 对象 */
/* 该对象有一个传参,参数为函数,而函数又有两个参数,
   分别为 resolve 和 reject,它们也是两个函数。 */
new Promise((resolve,reject)=>{
    $.ajax({
        url: 'url_1',
        success(data) {
            resolve(data)  //调用 resolve(),并把数据传入。
        },
        error() {
            reject("请求失败!")
        }
    })
}).then((data)=>{
    var url_2 = data.url
    return new Promise((resolve,reject)=>{
        $.ajax({
            url: 'url_2',
            success(data) {
                resolve(data)  //请求成功执行回调,把 data 传入 resolve()。
            },
            error() {
                reject("请求失败!") //请求失败执行 reject()。
            }
        })
    })
}).then((data)=>{
    console.log(data)  //执行 resolve() 后回调 then(),在这里处理拿到的数据。
}).catch((e)=>{
    console.log(e);   //执行 reject(),回调 catch() 捕获异常。
})

可以看到修改后的代码看起来就一目了然,我们在主动调用 resolve() 后会自动在后面回调 then() 方法,在 then() 方法中我们可以对传过来的数据进行处理,而把网络请求的部分放在前面的 Promise 对象中,这就实现了请求和结果分离,这样,今后无论我们有多少层嵌套,很容易就能对代码进行改动和维护。

总结

简单来说,Promise 就是通过对异步操作的封装,把网络请求和结果处理进行分离,用链式编程的方式使代码更加易于阅读和维护。