从Promise基础到手写,亲手打造异步编程神器
2024-01-15 07:21:44
前言
在现代Web开发中,异步编程已经成为一种常态。为了处理异步操作,JavaScript提供了一系列的API,其中Promise就是其中之一。Promise是一种用于处理异步操作的强大工具,它可以使代码更加清晰易读,并避免回调地狱。
Promise简介
Promise最早就出现时是为了解决编程中的异步行为导致的回调地狱。在没有Promise之前,对于函数的异步行为,一般采用回调函数的方式,在一个函数调用结束触发回调函数,这样会导致代码非常难以阅读和维护。为了解决这个问题,Promise应运而生。
Promise是一个对象,它表示一个异步操作的最终完成(或失败)及其结果值。我们可以通过Promise来跟踪异步操作的状态,并在操作完成后执行相应的操作。
Promise的基本用法
使用Promise非常简单,我们只需要按照以下步骤操作即可:
- 创建一个Promise对象,这个对象表示一个异步操作。
- 在Promise对象上调用then()方法,传入两个函数作为参数,这两个函数分别是成功回调函数和失败回调函数。
- 当异步操作成功完成后,Promise对象就会调用成功回调函数,并将操作结果作为参数传递给该函数。
- 如果异步操作失败,Promise对象就会调用失败回调函数,并将错误信息作为参数传递给该函数。
以下是一个使用Promise的简单示例:
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Hello, Promise!');
}, 2000);
});
promise.then((result) => {
console.log(result); // 输出: Hello, Promise!
});
在这个示例中,我们首先创建了一个Promise对象,并在构造函数中传入了一个函数作为参数。这个函数有两个参数,分别是resolve和reject。resolve表示异步操作成功,reject表示异步操作失败。
然后,我们调用Promise对象的then()方法,传入两个函数作为参数。第一个函数是成功回调函数,当异步操作成功完成后,Promise对象就会调用这个函数,并将操作结果作为参数传递给该函数。第二个函数是失败回调函数,如果异步操作失败,Promise对象就会调用这个函数,并将错误信息作为参数传递给该函数。
最后,我们调用setTimeout()方法来模拟一个异步操作。2秒后,我们调用resolve()方法来表示异步操作成功,并将'Hello, Promise!'作为操作结果传递给该方法。
Promise的链式调用
Promise支持链式调用,这使得我们可以将多个异步操作连接起来,形成一个异步操作队列。当一个异步操作完成后,下一个异步操作就会自动执行。
以下是一个使用Promise链式调用的示例:
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Hello, Promise!');
}, 2000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('I am Promise!');
}, 1000);
});
promise1.then((result) => {
console.log(result); // 输出: Hello, Promise!
return promise2;
}).then((result) => {
console.log(result); // 输出: I am Promise!
});
在这个示例中,我们首先创建了两个Promise对象,promise1和promise2。然后,我们调用promise1的then()方法,传入两个函数作为参数。第一个函数是成功回调函数,当promise1成功完成后,Promise对象就会调用这个函数,并将操作结果作为参数传递给该函数。第二个函数是失败回调函数,如果promise1失败,Promise对象就会调用这个函数,并将错误信息作为参数传递给该函数。
在成功回调函数中,我们返回promise2。这表示当promise1成功完成后,下一个异步操作就是promise2。然后,我们调用promise2的then()方法,传入两个函数作为参数。第一个函数是成功回调函数,当promise2成功完成后,Promise对象就会调用这个函数,并将操作结果作为参数传递给该函数。第二个函数是失败回调函数,如果promise2失败,Promise对象就会调用这个函数,并将错误信息作为参数传递给该函数。
最后,我们调用setTimeout()方法来模拟两个异步操作。2秒后,我们调用resolve()方法来表示promise1成功,并将'Hello, Promise!'作为操作结果传递给该方法。1秒后,我们调用resolve()方法来表示promise2成功,并将'I am Promise!'作为操作结果传递给该方法。
Promise的错误处理
在使用Promise的过程中,我们可能会遇到异步操作失败的情况。为了处理这种情况,我们需要在then()方法中传入一个失败回调函数。当异步操作失败时,Promise对象就会调用这个函数,并将错误信息作为参数传递给该函数。
以下是一个使用Promise错误处理的示例:
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('Oops, something went wrong!'));
}, 2000);
});
promise.then(null, (error) => {
console.log(error.message); // 输出: Oops, something went wrong!
});
在这个示例中,我们首先创建了一个Promise对象,并在构造函数中传入了一个函数作为参数。这个函数有两个参数,分别是resolve和reject。resolve表示异步操作成功,reject表示异步操作失败。
然后,我们调用Promise对象的then()方法,传入两个函数作为参数。第一个函数是成功回调函数,当异步操作成功完成后,Promise对象就会调用这个函数,并将操作结果作为参数传递给该函数。第二个函数是失败回调函数,如果异步操作失败,Promise对象就会调用这个函数,并将错误信息作为参数传递给该函数。
在失败回调函数中,我们打印错误信息。
手写Promise
现在我们已经了解了Promise的基本用法,那么我们就可以尝试自己手写一个简易的Promise了。
首先,我们需要定义一个Promise构造函数,这个构造函数有两个参数,分别是resolve和reject。resolve表示异步操作成功,reject表示异步操作失败。
function Promise(executor) {
this.state = 'pending';
this.result = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (result) => {
if (this.state !== 'pending') return;
this.state = 'fulfilled';
this.result = result;
this.onFulfilledCallbacks.forEach((callback) => callback(result));
};
const reject = (error) => {
if (this.state !== 'pending') return;
this.state = 'rejected';
this.result = error;
this.onRejectedCallbacks.forEach((callback) => callback(error));
};
executor(resolve, reject);
}
然后,我们需要定义then()方法。then()方法有两个参数,分别是成功回调函数和失败回调函数。
Promise.prototype.then = function(onFulfilled, onRejected) {
return new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
setTimeout(() => {
try {
const result = onFulfilled(this.result);
resolve(result);
} catch (error) {
reject(error);
}
}, 0);
} else if (this.state === 'rejected') {
setTimeout(() => {
try {
const result = onRejected(this.result);
resolve(result);
} catch (error) {
reject(error);
}
}, 0);
} else {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const result = onFulfilled(this.result);
resolve(result);
} catch (error) {
reject(error);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const result = onRejected(this.result);
resolve(result);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
};
最后,我们需要定义catch()方法。catch()方法只有一个参数,即失败回调函数。
Promise.prototype.catch = function(onRejected) {
return this.then(null, onRejected);
};
现在,我们就可以使用我们自己手写的Promise了。以下是一个使用我们自己手