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 包含两个函数参数:
第一个函数的参数接收 Promise 容器中的 resolve 抛出的成功内容第二个函数的参数接收 Promise 容器中的 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')
}
文章已同步我的个人博客:《Callback Hell和ECMAScript6 Promise》