“回调地狱”是一种前端开发常见的问题现象,为了解决这一问题,ES6引入了Promise,什么是Promise ?具体如何使用?本文将会针对这些问题进行分析,对Promise进行探究。
一、回调地狱
存在异步的两个方法A和B,而B的执行需要依据A执行完毕后的结果,B此时就是A的回调函数,如果涉及的异步执行方法很多,A->B->C->D....,就会产生所谓的“回调地狱”现象。举例说明如下:
function ajaxDemo(){
$.ajax({
type : "POST",
url : "",
data : {
},
success : function(resultA) {
//根据resultA做一些业务判断,参数转化等
$.ajax({
type : "POST",
url : "",
data : {
},
success : function(resultB) {
//根据resultB做一些业务判断,参数转化等
$.ajax({
type : "POST",
url : "",
data : {
},
success : function(resultC) {
//根据resultC做一些业务判断,参数转化等
//...........
}
});
}
});
}
});
}
这样就会造成代码可读及维护性很差,接下来要说的Promise是怎么解决这种问题的。
二、Promise是什么
在介绍Promise之前,先了解一下javascript异步编程发展历史:
1、当一个JavaScript应用在运行的时候,它会以单线程的方式运行,这样避免了开发人员为多线程编程中可能出现的棘手问题而担心。 2、不过这种自由是有条件的:为了写出能够流畅运行的软件,必须考虑异步,而不仅仅是用户输入。 3、JavaScript对异步编程的支持有三个不同的阶段:回调(callback)阶段、promise(承诺)阶段和生成器(generator)阶段。 4、生成器本身并不提供任何对异步的支持:它们依赖于承诺或特定类型的回调来提供异步行为。同样,像承诺这样有用的东西,会依赖于回调(而回调本身又由于具有对象而变得更有用)。 |
摘自:《JavaScript学习指南(第3版)》【美】Ethan Brown
从上述文字中,可以知道无论是回调还是承诺,都是javascript异步编程的一种方式,而且承诺会依赖回调,这也让我们明白:技术的发展是有相关性的,不能独立看待。
那Promise是什么?
Promise是JavaScript第一个标准的异步模型,包含传递信息与状态的对象,拥有以下两个特点: |
摘自:《JavaScript框架设计(第2版)》司徒正美
摘取书中“http请求”代码案例:
function get(url) {
return new Promise(function(resolve, reject){
var req = new XMLHttpRequest();
req.open('GET',url);
req.onload = function() {
if (req.status == 200) {
resolve(req.response);
}else {
reject(Error(req.statusText));
}
};
req.onerror = function() {
reject(Error("Network Error"));
};
req.send();
});
}
get('story.json').then(function(response) {
console.log("Success!", response);
},function(error) {
console.error("Failed!", error);
});
这个案例清晰的介绍了Promise的实现思路:Promise构造httpGet请求,get('story.json')进入Pending状态,运行结果成功变成Resolved状态,调用resolve方法;运行结果失败或者异常时调用进入Rejected状态调用reject方法。
三、Promise使用
这一部分将会例举Promise几种常用使用方式:
- 链式使用 Promise
const fetchPromise = fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');
fetchPromise
.then( response => {
return response.json();
})
.then( json => {
console.log(json[0].name);
});
- 异常捕获
const fetchPromise = fetch('bad-scheme://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');
fetchPromise
.then( response => {
if (!response.ok) {
throw new Error(`HTTP 请求错误:${response.status}`);
}
return response.json();
})
.then( json => {
console.log(json[0].name);
})
.catch( error => {
console.error(`无法获取产品列表:${error}`);
});
- 合并使用多个Promise
const fetchPromise1 = fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');
const fetchPromise2 = fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/not-found');
const fetchPromise3 = fetch('https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json');
Promise.all([fetchPromise1, fetchPromise2, fetchPromise3])
.then( responses => {
for (const response of responses) {
console.log(`${response.url}:${response.status}`);
}
})
.catch( error => {
console.error(`获取失败:${error}`)
});
- async 和 await
async function fetchProducts() {
try {
const response = await fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');
if (!response.ok) {
throw new Error(`HTTP 请求错误:${response.status}`);
}
const json = await response.json();
return json;
}
catch(error) {
console.error(`无法获取产品列表:${error}`);
}
}
const jsonPromise = fetchProducts();
jsonPromise.then((json) => console.log(json[0].name));
代码示例摘自:如何使用 Promise - 学习 Web 开发 | MDN
Promise分析的就到这里,希望对你有所帮助。