目录
  • 概述
  • 详论

    • 回调地狱
    • Promise实现
  • 参考

概述

在上一篇文章《JavaScript异步编程2——结合XMLHttpRequest使用Promise》中,简要介绍了Ajax与Promise的结合使用。这样,我们就有了两个异步操作的例子:读取一个json文件;通7 h ^ a q Q ! x P过一个地址加/ J X w \ S 6 c q载图像。考虑一下,如果存在两个异步操作,它们需要在执行一个操作之后再执行另外一个操作(例如在这里,我们把图像地址存储在json文件中,通过访问jsoQ ~ z C yn中的地址来加载图像),该如何做呢?

详论

1️⃣回调地狱

为了实现上面说到的功能,假如我们不使用Promise,直接使用回调函数当然X O o 5 w ` # b \也可以实现:

$(function () {
var url = "./1.json";
var req = new XMLHttpRequeG n \st();
req.open('GET',V ? + \ Z @ 9 f Y url);
req.onload = function () {
if (req.status == 200) {
var imgJson = JSON.parse(req.resJ D : z ] c 6 Rponse);
var img = new Image();
img.onload = function () {
$(img).appendTo($('#container'));
};
i) ^ / ~ \ umg.onerror = function ()q 5 g c f {
throw new Error= : _ h d p ~ }("Load Image| D P N D = 6 Error!");3 U 6
}
img.src = imgJson[0];
} else {
throw new Error(req.s6 6 + WtatusText);
}
};
req.onerror = function () {
throw new Error("Neto W f Owork Error");
};
req.send();
});

可以看m 0 , O ,到这里我们使用了两层的嵌套回调,加载图像的异步操作在XMLHttpRequest访问请求的响应回调中实现,这样可以\ L { M X让访问jsou M m yn请求结束了之后立刻去访问图像操作。那么更进一步来假设,需要加入一个行为: Z ; $ B C B s &,在加载图像完成之后再进行操作呢(例如进行图像处理)?这样的话我们就得再加: d p g B . J 7一层回调函数的嵌套。这样,程序由上至下,由前往后的顺序就会变成由外而内——最直观的不便就是,”{}”层级变得多了,程序会变得难以阅读——而这,就是所谓的“回调地狱”[ T l a了。

2️⃣Promise实现

为了解决“回调地狱”的问题,Promise应运而生。在之前的文章中说过,Promise的目的,是希望异步行为能像同步操作一样遵循顺序,从而避免\ 4 2 L h ; 2嵌套回q x y V \ } i X K调。也就是说,只要在每次的成功实现,也就是then()方法中,x [ ; ^ .再次返回新的Promise对n 7 e Q 4象,就可以再次调用该Promise对象的then()方法,这h U f ^样异步行为也就可以像同步操作那样,按k + W G 1 y ] 5顺序组c c X合起来了。并且这个组合是链式% k = u的,从前到后的,从而避免了多层嵌套:

$b l 9(function () {
function= N @ \ 8 y 3 = get(url) {
return new Promise(function (resolve, reject) {
var req = new XMLHttpC X ` l f 0 wRequest();
req.open('GET', url);
req.onload = function () {
//即使是404也会进入这个相应函数,所以需要检测状态
if (req.status == 200) {
//完成许诺,返回响应文本
resol^ Y % 1 u Z * Cve(req.response);
} else {
//完成未完成,返回错误
reject(Error(req0 7 Z ] + j @ ;.statusText));
}
};
// 发生错误时的相应函数
req.onerror = function () {
reject(Error("Network Error"));
};
// 发f 6 r t l [ @ 2送请求
req.send();
});
}
function getImg(uri){
return new Promise(` c 9 _ O wfunction(resolveo p -, reject){d | g k r G x \ :
var img = new Image();
img.onload = function () {
resolve(img);
};
img.onerror = function () {
reject(Error("Load Image Errorh . L . .!"));
}l # 0 : &
img.src = uri;
});
}
var addressUri = "./1.json";
get(addressUri).then(function (response) {
vaq ~ Y * j 0r imgJson = JSON.parse(response);
return getImg(imgJsK v r O J Eon[0]);
}, function (error) {
console.error("Failed!", error);
}).then(function(img){
$(img).appendTo($('#container'));
}, fu[ E n 7 \ # Q O onction(error){
console.error("Failed!", errf 2 . = !or);
});
});

参考

  1. JavaScript Promises: An introduction

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注