一、Promise基本概念
Promise 是异步编程的一种解决方案,用于处理异步操作。ES6 的 Promise 规范,是对异步编程的一种规范化,使得编写和维护异步程序更加容易、直观。
Promise 是一个对象,它代表了一个异步操作的最终结果。它可以是下列三种状态之一:等待态(pending)、完成态(fulfilled)、拒绝态(rejected)。
Promise 的优点在于可以避免“回调地狱”,使得代码结构清晰,更具有可读性和可维护性。
二、Promise基本用法
ES6 新增了 `Promise` 构造函数,可以使用 `new Promise()` 来创建一个 Promise 对象。
let promise = new Promise(function(resolve, reject){
//异步操作的代码
//成功时调用 resolve()
//失败时调用 reject()
})
当 Promise 对象的状态发生改变时,会产生对应的回调函数。可以使用 `promise.then()` 方法来指定 Promise 对象状态变为 fulfilled 或 rejected 时调用的回调函数。这两个方法都返回一个新的 Promise 对象,可以进行链式调用。
let promise = new Promise(function(resolve, reject){
setTimeout(() => resolve("异步操作成功"), 1000);
})
promise.then(res => {
console.log(res); //异步操作成功
})
三、Promise原理
Promise 的基本原理就是对异步操作进行封装,使其可以返回一个 Promise 对象,并可以使用链式调用方法。
我们可以手动模拟一下 Promise 的内部实现:
function Promise_old(fn){
let state = 'pending';
let value = null;
let callbacks = [];
this.then = function(onFulfilled){
return new Promise_old(function(resolve){
handle({
onFulfilled: onFulfilled || null,
resolve: resolve
})
})
}
function handle(callback){
if(state === 'pending'){
callbacks.push(callback);
return;
}
if(!callback.onFulfilled){
callback.resolve(value);
return;
}
let ret = callback.onFulfilled(value);
callback.resolve(ret);
}
function resolve(newValue){
if(newValue && (typeof newValue === 'object' || typeof newValue === 'function')){
let then = newValue.then;
if(typeof then === 'function'){
then.call(newValue, resolve);
return;
}
}
setTimeout(function(){
state = 'fulfilled';
value = newValue;
callbacks.forEach(function(callback){
handle(callback);
})
}, 0);
}
fn(resolve);
}
上述代码中,我们定义了 `Promise_old` 构造函数。它内部定义了 `state`、`value`、`callbacks` 三个变量,分别记录 Promise 对象的当前状态、结果值和对应回调函数数组。同时我们定义了 `then` 方法,可以使用链式调用,将传入的回调函数压入 `callbacks` 数组中。
关键的 `handle` 函数则利用了 JavaScript 的事件循环机制,当 Promise 对象的状态从 `pending` 改变时,依次执行队列中的回调函数。
最后通过 `resolve` 函数,可以修改 Promise 对象的状态,触发对应回调函数的执行。
四、Promise实例应用
1、串行异步任务的处理
使用 `Promise` 可以让多个异步任务按顺序执行,比如读取多个文件,顺序进行操作。这里我们演示一个例子,读取两个文件,分别将其内容存放在一个数组中。
let fs = require('fs');
function readFile(filename){
return new Promise(function(resolve, reject){
fs.readFile(filename, 'utf8', function(err, data){
if(err){
reject(err);
return;
}
resolve(data);
})
})
}
Promise.all([
readFile('file1.txt'),
readFile('file2.txt')
]).then(function(dataArr){
console.log(dataArr); //[data1, data2]
})
2、并发异步任务的处理
有时候需要同时执行多个异步任务,可以使用 `Promise.all()` 方法,将返回值存放在数组中按顺序返回。
let dataArr = [];
function fetchData(url){
return new Promise((resolve, reject) => {
fetch(url)
.then(res => res.json())
.then(data => {
dataArr.push(data);
resolve(data);
})
.catch(error => reject(error))
})
}
Promise.all([
fetchData('https://api.xxx.com/1'),
fetchData('https://api.xxx.com/2'),
fetchData('https://api.xxx.com/3')
]).then(() => {
console.log(dataArr); //[data1, data2, data3]
})
3、Promise异常处理
使用 `then()` 方法时,可以链式调用多个回调函数,并在其中任何一个回调函数中引发错误,就会被 `catch()` 方法捕获。如果在 `then()` 方法中不使用回调函数,就必须在链头使用 `catch()` 方法来进行异常处理。
function fetchData(){
return new Promise((resolve, reject) => {
//使用 Math.random() 模拟程序执行时出现错误
if(Math.random() > 0.5){
resolve('fetch data success');
} else {
reject('fetch data failed');
}
})
}
//这个方法捕获了两个 Promise 对象中的异常,并输出错误信息
fetchData().then(res => {
console.log(res);
}).catch(error => {
console.log(error);
})
结束语
Promise 是异步编程的一种新规范,提高了代码的可读性、可维护性和稳定性。通过上述的介绍和实例,希望读者能够深入了解 Promise 的基本原理和使用方法,高效编写异步代码。