1.ES6 Promise的概念和作用
在ES6中,Promise是一种异步编程的解决方案,它提供了一种更加优雅的方式来处理异步操作,解决了回调函数嵌套的问题,让异步代码更加易读、易维护。Promise是一种对象,它代表了一个异步操作的最终完成或失败,并可以返回异步操作的结果或错误信息。
Promise的作用是将异步操作封装成一个函数,并返回一个Promise对象。这个对象可以调用then()方法来注册异步操作成功时的回调函数,也可以调用catch()方法来注册异步操作失败时的回调函数。
2.Promsie的基本语法
2.1 创建Promise
Promise的创建语法为:new Promise(fn),其中fn是一个带有resolve和reject两个参数的函数,resolve表示异步操作成功时的回调函数,reject表示异步操作失败时的回调函数。下面是一个示例代码:
let promise = new Promise(function(resolve, reject) {
setTimeout(function() {
let randomNum = Math.random();
if (randomNum > 0.5) {
resolve('success');
} else {
reject('error');
}
}, 1000);
});
上述代码中,当执行到setTimeout函数时,它会先等待1秒,然后随机生成一个0~1之间的随机数,如果随机数大于0.5,则执行resolve('success'),表示异步操作成功,并返回一个成功的Promise对象,否则执行reject('error'),表示异步操作失败,并返回一个失败的Promise对象。调用方式如下:
promise.then(function(result) {
console.log(result);
}).catch(function(error) {
console.log(error);
});
上述代码中,调用then()方法注册异步操作成功时的回调函数,如果异步操作成功,此时result就是resolve函数的返回值,即'success'。调用catch()方法注册异步操作失败时的回调函数,如果异步操作失败,此时error就是reject函数的返回值,即'error'。
2.2 Promise.all
Promise.all()方法接收一个Promise对象数组作为参数,返回一个新的Promise对象,当数组中所有的Promise对象都成功后,将会调用then()方法处理成功的结果,如果有一个失败了,就会调用catch()方法处理失败的结果。
let promise1 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('1000ms');
}, 1000);
});
let promise2 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('3000ms');
}, 3000);
});
let promise3 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('2000ms');
}, 2000);
});
Promise.all([promise1, promise2, promise3])
.then(function (result) {
console.log(result);
})
.catch(function (error) {
console.log(error);
});
上述代码中,Promise.all()方法接收一个数组,这个数组里面包含了三个Promise对象。我们在数组里面定义了三个Promise对象,每个Promise对象都模拟了一个异步操作,分别是等待1秒、3秒和2秒。由于promise2需要等待3秒才会返回结果,所以整个数组需要等待3秒才会调用then()方法处理Promise成功的结果。
3.Promise的错误处理
Promise对象有一个catch()方法,用来处理Promise对象的异步操作失败情况。如果在Promise对象中执行发生错误,则捕获错误信息,并调用catch()方法对错误信息进行处理。
let promise = new Promise(function(resolve, reject) {
setTimeout(function() {
try {
throw new Error('error!!!');
} catch (e) {
reject(e);
}
}, 1000);
});
promise.catch(function(error) {
console.log(error);
});
在上述代码中,由于执行过程中抛出了一个错误,所以会执行到catch()方法并处理错误信息。下面是输出的结果:
Uncaught (in promise) Error: error!!!
at setTimeout (VM527:4)
可以看到,输出了一个错误信息,即“Uncaught (in promise) Error: error!!! at setTimeout (VM527:4)”,其中“Uncaught”表示未捕获的异常。
4.Promise的链式调用
Promise对象的then()方法可以链式调用,即在成功的回调函数内返回一个Promise对象,可以继续调用then()方法。这种情况下,后一个Promise对象的状态就是前一个Promise对象的状态。
var p1 = new Promise(function(resolve, reject) {
resolve('p1');
});
var p2 = new Promise(function(resolve, reject) {
resolve('p2');
});
var p3 = new Promise(function(resolve, reject) {
resolve('p3');
});
p1.then(function(result) {
console.log(result);
return p2;
}).then(function(result) {
console.log(result);
return p3;
}).then(function(result) {
console.log(result);
});
在上述代码中,定义了三个Promise对象:p1、p2和p3,然后通过p1.then()方法调用p1成功时的回调函数。回调函数里面返回了一个Promise对象p2,又通过p2.then()方法调用p2成功时的回调函数,回调函数里面返回了一个Promise对象p3,又通过p3.then()方法调用p3成功时的回调函数。这样就形成了一个Promise对象的链式调用,在每个回调函数里面返回一个Promise对象,形成了Promise的串联。
5.Promise.race
Promise.race()方法也接收一个Promise对象数组作为参数,但是只要有一个Promise对象状态发生变化,Promise.race()方法就会立即返回这个Promise对象的结果,无论它是成功还是失败。其他的Promise对象会被忽略。下面是一个简单的例子:
let promise1 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('1000ms');
}, 1000);
});
let promise2 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('3000ms');
}, 3000);
});
let promise3 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('2000ms');
}, 2000);
});
Promise.race([promise1, promise2, promise3])
.then(function (result) {
console.log(result);
})
.catch(function (error) {
console.log(error);
});
上述代码中,Promise.race()方法接收了一个包含了三个Promise对象的数组作为参数,其中promise2需要等待3秒才返回,但是由于Promise.race()只要有一个Promise对象状态发生变化就会立即返回,所以最终输出的结果是'1000ms'。
6.Promise的使用场景
Promise的使用场景非常广泛,比如异步加载图片,异步请求数据,异步保存数据等等。下面以异步请求数据为例:
function request(url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onload = function () {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response);
} else {
reject(xhr.statusText);
}
};
xhr.onerror = function () {
reject(xhr.statusText);
};
xhr.send();
});
}
request('https://jsonplaceholder.typicode.com/posts')
.then(function (data) {
console.log(data);
})
.catch(function (error) {
console.log(error);
});
上述代码中,request()函数使用XMLHttpRequest对象异步请求数据,成功时返回resolve(xhr.response),失败时返回reject(xhr.statusText)。然后调用request()函数获取数据,如果操作成功,则调用then()方法处理成功的结果,如果操作失败,则调用catch()方法处理失败的结果。
7.Promise的兼容性
Promise在ES6中被广泛使用,但是在一些旧的浏览器中可能不被支持,需要使用polyfill来进行兼容。Promise.polyfill()方法可以用来判断浏览器是否支持Promise,并自动加载相应的polyfill文件进行兼容处理。
下面是一个简单的兼容处理:
if (!window.Promise) {
window.Promise = Promise;
}
上述代码中,通过判断window对象中是否存在Promise方法,如果不存在则将Promise赋值给window.Promise。
8.总结
ES6中的Promise是一种异步编程的解决方案,它能够优雅地处理异步操作,解决了回调函数嵌套的问题。使用Promise可以更加易读、易维护,提高代码的可维护性和可读性。Promise的语法简单明了,常用的方法有Promise.all、Promise.race、then()方法和catch()方法。但是在一些旧的浏览器中不被支持,需要进行兼容处理。通过学习Promise这种新的异步编程方式,可以更好地掌握异步编程,并提高代码开发效率和质量。