Callback Hell和ECMAScript6 Promise

Promise 是 “14nodejs(7天)” 第五天的课程,但是 Promise 并不属于 Node.js 的内容,而是 ECMScript6 新增的 API

回调地域(Callback Hell)

回调地域一个异步请求需要另一个异步请求结果

$.ajax({url, success: function () { ... }})
$.ajax({url, success: function () { ... }})
$.ajax({url, success: function () { ... }})
$.ajax({url, success: function () { ... }})

由于 Javascript 是单线程的,所以这里执行顺序是 ajax1 -> ajax2 -> ajax3 -> ajax4

但是又由于这四个是异步操作,所以这种多线程操作会导致执行顺序不固定

为了保障异步函数的执行顺序,可以通过异步套异步的方式解决

$.ajax({url, success: function () {
    $.ajax({url, success: function () {
        $.ajax({url, success: function () {
            $.ajax({url, success: function () { ... }})
        }})
    }}) 
}})

以上这种写法就是所谓的回调地域,非常的不利于维护

为了解决这一情况, ECMAScript6 新增了 Promise API

Promise(承诺)

可以理解 Promise 为一个容器,它包含三个状态,分别为 Pending(正在执行)Resolved(已解决)Rejected(未解决)

Promise 本身并不是异步的,但其包裹的内容函数为异步函数

// 通过 new Promise 创建 Promise 容器
// 实例化 Promise
var p1 = new Promise (function (resolve, reject) { // Promise 容器(它本身不是异步方法)
    $.ajax({ // $.ajax 异步方法
        url,
        success: function () {
            resolve(data) // 改变容器状态为成功
        },
        error: function () {
            reject(err) // 改变容器状态为失败
        }
    })
})

容器接收两个形参:

resolve
reject

通过 .then() 决定实例成功后的指定操作

p1.then(function (data) {
    console.log(data) // 接收 p1 实例成功状态 resolve 抛出的数据 data 
    return p2 // 返回第二个 Promise 容器
}, function (err) {
    console.log(err) // 接收 p1 实例失败状态 reject 抛出的数据 data
})

.then 包含两个函数参数:

resolve
reject

.then 的第一个函数中可以返回数据,此数据可以提供给后续 .then 接收使用

  • 如果没有 return 返回值,则后续接收到 undefined
  • 如果 return 返回一个 Promise 对象时,后续 .then 第一个函数接收该 Promise 对象的 resolve 状态,第二个函数接收该 Promise 对象的 reject 状态

到此,通过以上的介绍可以 优化回调地域(Callback Hell)

// 通过 new Promise 创建 Promise 容器
// 实例化 Promise
var p1 = new Promise (function (resolve, reject) { // Promise 容器(它本身不是异步方法)
    $.ajax({ // $.ajax 异步方法
        url,
        success: function () {
            resolve(data) // 改变容器状态为成功
        },
        error: function () {
            reject(err) // 改变容器状态为失败
        }
    })
})
var p2 = new Promise (function (resolve, reject) { ... })
var p3 = new Promise (function (resolve, reject) { ... })
var p4 = new Promise (function (resolve, reject) { ... })
// 操作实例
p1
    .then(function (data) {
        console.log(data) // 打印 p1 的 data 内容
        return p2 // 向下传递实例 p2
    }, function (err) {
        console.log(err) // 打印 p1 的 err 信息
    })
    .then(function (data) {
        console.log(data) // 打印 p2 的 data 内容
        return p3 // 向下传递实例 p3
    }, function (err) {
        console.log(err) // 打印 p2 的 err 信息
    })
    .then(function (data) {
        console.log(data) // 打印 p3 的 data 内容
        return p4 // 向下传递实例 p4
    }, function (err) {
        console.log(err) // 打印 p3 的 err 信息
    })
    .then(function (data) {
        console.log(data) // 打印 p4 的 data 内容
    }, function (err) {
        console.log(err) // 打印 p4 的 err 信息
    })

通过判断是否有 then 方法判断其是否是 Promise 对象

var p1 = new Promise (function (resolve, reject) { ... }
function p2 () { ... }
// 替换下段代码中的 fn 即可查看 P1、P2 是否是 Promise 对象
if (!!fn && typeof fn.then === 'function') {
    console.log('是Promise')
} else {
    console.log('不是Promise')
}

文章已同步我的OSCHINA社区:《[Callback Hell和ECMAScript6 Promise]》

我来评几句
登录后评论

已发表评论数()

相关站点

热门文章