1. Promise基础概念
Promise是一种用来处理异步操作的简单对象,它代表了异步操作的最终完成或失败,并返回结果值或抛出异常。一个Promise一般有三种状态:pending、fulfilled和rejected。当Promise对象的异步操作成功时,它的状态变为fulfilled;当Promise对象的异步操作失败时,它的状态变为rejected。一旦一个Promise对象的状态变为fulfilled或rejected,它们就不会再发生变化,此后任何时候对Promise对象的任何操作都是无效的。
1.1 创建Promise
创建一个Promise对象非常简单,只需要调用Promise的构造函数,并传入一个函数作为参数。这个函数被称为“执行器函数”,它接受两个函数参数:resolve和reject。当Promise状态变为fulfilled时,执行器函数应该调用resolve函数并将结果作为参数传递给它,而当Promise状态变为rejected时,则应该调用reject函数并将错误作为参数传递给它。下面是一个简单的Promise示例:
const promise = new Promise((resolve, reject) => {
// 异步操作代码
if (/* 异步操作成功 */) {
resolve(result);
} else {
reject(error);
}
});
1.2 Promise链式调用
Promise一般都是通过链式调用来实现多个异步操作的有序执行,每个异步操作的结果都会被传递到下一个异步操作中。为了实现链式调用,Promise实例对象必须返回自身对象。下面是一个简单的Promise链式调用示例:
const promise = new Promise((resolve, reject) => {
// 异步操作代码
if (/* 异步操作成功 */) {
resolve(result1);
} else {
reject(error1);
}
}).then((result1) => {
// 处理result1
return result2; // 返回一个新的Promise
}).then((result2) => {
// 处理result2
return result3; // 返回一个新的Promise
}).catch((error) => {
// 处理错误
}).finally(() => {
// 总是执行的代码
});
在上面的示例中,promise对象中第一个执行器函数会返回一个新的promise对象,然后新的promise对象会被传递给第一个then方法。第一个then方法会处理新的promise对象成功状态下的返回值,并返回一个新的promise对象,然后新的promise对象会被传递给第二个then方法。第二个then方法也会处理新的promise对象成功状态下的返回值,并返回一个新的promise对象,依此类推。如果链式调用中任意一个promise对象被拒绝了,它后面的所有方法都会被跳过,直到遇到catch或finally方法。如果链式调用中没有catch方法,错误将会被抛出。
2. Promise高级用法
2.1 Promise.all
Promise.all方法可以接收一个 Promise 对象的iterable(如数组),返回一个新的 Promise 对象。当所有的 Promise 对象都变为成功状态时,Promise.all返回的 Promise 对象就变为成功状态,并将每个 Promise 对象的返回值作为一个数组返回给then方法;如果其中任一一个 Promise 对象变为失败状态,Promise.all返回的 Promise 对象就变为失败状态,并将第一个失败的 Promise 对象的错误信息返回给catch方法。
Promise.all([promise1, promise2, promise3])
.then((results) => {
// 处理结果
})
.catch((reason) => {
// 处理异常
})
在上面的示例中,Promise.all会等待promise1、promise2和promise3都变为成功状态时,才会调用then方法;如果其中一个或多个Promise对象变为失败状态,就会立即调用catch方法并返回失败的Promise对象的错误信息。
2.2 Promise.race
Promise.race方法和Promise.all方法类似,它也是接收一个 Promise 对象的iterable(如数组),返回一个新的 Promise 对象。当iterable中任意一个 Promise 对象变为成功状态时,Promise.race方法返回的 Promise 对象就变为成功状态,并将第一个 Promise 对象的返回值作为then方法的参数;如果其中任一一个 Promise 对象变为失败状态,Promise.race方法返回的 Promise 对象就变为失败状态,并将第一个失败的 Promise 对象的错误信息返回给catch方法。
Promise.race([promise1, promise2, promise3])
.then((result) => {
// 处理结果
})
.catch((reason) => {
// 处理异常
})
在上面的示例中,Promise.race会等待promise1、promise2和promise3中任意一个 Promise 对象变为成功状态或失败状态时,才会调用then方法或catch方法。
2.3 Promise.resolve
Promise.resolve方法可以接收一个value值或一个 Promise 对象,并返回一个新的 Promise 对象,这个 Promise 对象会立即变为成功状态,并将value值或者 Promise 对象的返回值作为then方法的参数。
Promise.resolve(value)
.then((result) => {
// 处理结果
})
在上面的示例中,Promise.resolve会立即返回一个成功状态的Promise对象,并将value作为then方法的参数。
2.4 Promise.reject
Promise.reject方法可以接收一个error错误信息,并返回一个新的 Promise 对象,这个 Promise 对象会立即变为失败状态,并将error错误信息作为catch方法的参数。
Promise.reject(error)
.catch((reason) => {
// 处理异常信息
})
在上面的示例中,Promise.reject会立即返回一个失败状态的Promise对象,并将error作为catch方法的参数。
3. Promise使用实例
3.1 实现图片预加载
下面是一个简单的实现图片预加载的示例,该示例使用Promise.all方法实现了多张图片预加载,当所有图片都被成功加载时,将它们一次性添加到页面中的img元素中。
const imageUrls = ['http://example.com/image1.jpg', 'http://example.com/image2.jpg', 'http://example.com/image3.jpg'];
const promises = imageUrls.map((imageUrl) => {
return new Promise((resolve, reject) => {
const image = new Image();
image.onload = () => {
resolve(image);
};
image.onerror = () => {
reject(new Error(`图片加载失败 ${imageUrl}`));
};
image.src = imageUrl;
});
});
Promise.all(promises)
.then((images) => {
const imageContainer = document.getElementById('image-container');
images.forEach((image) => {
const imgElement = document.createElement('img');
imgElement.src = image.src;
imgElement.alt = '预加载图片';
imageContainer.appendChild(imgElement);
});
})
.catch((error) => {
console.error('图片加载错误:', error);
});
在上面的示例中,我们通过map方法遍历所有的图片链接,创建了一系列Promise对象并添加到了promises数组中。然后使用Promise.all方法等待这些Promise对象都变为成功状态或失败状态时,才会执行后面的then方法或catch方法。在then方法中,我们通过forEach方法遍历所有的图片,创建一个新的img元素,并将其添加到页面中。
3.2 获取异步操作的结果
下面是一个简单的实现一个异步操作得到结果的示例,该示例使用Promise对象的then方法处理异步操作成功的结果。
function fetchData(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
resolve(xhr.responseText);
} else {
reject(new Error(`请求失败 ${xhr.status}`));
}
}
};
xhr.send();
});
}
fetchData('http://example.com/data.json')
.then((data) => {
console.log('data:', data);
})
.catch((error) => {
console.error('请求错误:', error);
});
在上面的示例中,我们通过XMLHttpRequest对象获取一个JSON文件,并返回一个Promise对象。然后通过then方法处理Promise对象成功状态下的返回值,并输出到控制台中;通过catch方法处理Promise对象失败状态下的错误信息,并输出到控制台中。
3.3 模拟ajax请求
下面是一个简单的实现模拟ajax请求的示例,该示例使用Promise对象的resolve方法和setTimeout函数模拟异步地向服务器发送请求和获取结果。
function ajax(url, options) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
setTimeout(() => {
resolve(xhr.responseText);
}, options.timeout || 0);
} else {
reject(new Error(`请求失败 ${xhr.status}`));
}
}
};
xhr.open(options.method || 'GET', url, true);
for (const key in options.headers) {
if (options.headers.hasOwnProperty(key)) {
xhr.setRequestHeader(key, options.headers[key]);
}
}
xhr.send(options.body || null);
});
}
ajax('http://example.com/data.json', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({name: 'jerry', age: 18}),
timeout: 1000
})
.then((result) => {
console.log('请求结果:', result);
})
.catch((error) => {
console.error('请求失败:', error);
});
在上面的示例中,我们通过XMLHttpRequest对象向服务器发送一个POST请求,并返回一个Promise对象。然后通过resolve方法模拟异步返回结果,并在then方法中处理成功状态下的结果;通过reject方法返回错误信息,并在catch方法中处理失败状态下的错误信息。