点击在线浏览,体验更好 | 链接 |
---|---|
古代JavaScript高级小册 | 链接 |
深入浅出Dart | 链接 |
古代TypeScript高级小册 | 链接 |
实现合乎Promise/A+标准的Promise
介绍:
Promise是JavaScript中解决异步操作的重要工具之一。Promise/A+标准是一种对于Promise实现的规范,它定义了Promise的行为和办法。本文将具体介绍如何实现Promise/A+标准,让你理解Promise的工作原理并可能本人实现一个符合规范的Promise。
Promise/A+标准简介
1. Promise的三种状态:
- pending(进行中):Promise的初始状态,示意异步操作正在执行。
- fulfilled(已实现):异步操作胜利实现,并返回一个值,称为解决值(fulfillment value)。
- rejected(已回绝):异步操作失败或被回绝,并返回一个起因(reason),通常是一个谬误对象。
2. 状态转换:
- Promise的状态只能从pending转变为fulfilled或rejected,一旦转变就不可逆转。
- 状态转换是由异步操作的后果决定的。如果异步操作胜利实现,Promise的状态会转变为fulfilled;如果异步操作失败或被回绝,Promise的状态会转变为rejected。
3. Promise的根本办法:
then
办法:用于注册异步操作胜利实现时的回调函数,并返回一个新的Promise对象。它承受两个参数:onFulfilled(可选,异步操作胜利时的回调函数)和onRejected(可选,异步操作失败时的回调函数)。catch
办法:用于注册异步操作失败时的回调函数,并返回一个新的Promise对象。它是then
办法的一个非凡模式,仅用于捕捉异样。finally
办法:无论异步操作胜利或失败,都会执行的回调函数,并返回一个新的Promise对象。它在Promise链中的最初执行,并且不接管任何参数。
4. 谬误冒泡和异样传递:
- Promise/A+标准要求Promise的谬误可能被适当地捕捉和解决。当一个Promise产生谬误时,它会向下流传,直到找到最近的谬误处理函数为止。
- 在Promise链中的任何一个Promise产生谬误,都会导致整个链上的谬误处理函数被调用,以便进行错误处理和复原。
遵循Promise/A+标准的实现应该具备上述个性,以确保统一的Promise行为和接口。这样,开发者能够编写通用的异步代码,而无需放心特定Promise实现的差异性。
实现Promise
当从零开始实现 Promise/A+ 标准的 Promise,咱们须要逐渐构建 Promise 的外围性能,包含状态治理、状态转换、回调解决和错误处理。
步骤 1: 创立 Promise 构造函数
首先,咱们须要创立一个 Promise 构造函数,它承受一个执行器函数作为参数。执行器函数承受两个参数,即 resolve 和 reject 函数,用于管制 Promise 的状态转换。
function MyPromise(executor) {
// TODO: 实现构造函数
}
步骤 2: 初始化 Promise 状态和回调
在构造函数中,咱们须要初始化 Promise 的状态和回调数组。状态能够应用一个变量来示意,初始值为 ‘pending’。回调数组用于存储注册的胜利和失败回调函数。
function MyPromise(executor) {
var self = this;
self.state = 'pending';
self.value = undefined;
self.reason = undefined;
self.onFulfilledCallbacks = [];
self.onRejectedCallbacks = [];
// TODO: 实现构造函数的其余部分
}
步骤 3: 实现 resolve 和 reject 函数
咱们须要实现 resolve 和 reject 函数,用于将 Promise 的状态从 ‘pending’ 转换为 ‘fulfilled’ 或 ‘rejected’。resolve 函数将传递一个值来兑现 Promise,而 reject 函数将传递一个起因来回绝 Promise。
function MyPromise(executor) {
var self = this;
self.state = 'pending';
self.value = undefined;
self.reason = undefined;
self.onFulfilledCallbacks = [];
self.onRejectedCallbacks = [];
function resolve(value) {
if (self.state === 'pending') {
self.state = 'fulfilled';
self.value = value;
self.onFulfilledCallbacks.forEach(function(callback) {
callback(self.value);
});
}
}
function reject(reason) {
if (self.state === 'pending') {
self.state = 'rejected';
self.reason = reason;
self.onRejectedCallbacks.forEach(function(callback) {
callback(self.reason);
});
}
}
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
步骤 4: 实现 then 办法
接下来,咱们须要实现 then 办法,用于注册胜利和失败的回调函数,并返回一个新的 Promise。then 办法承受两个参数:胜利回调函数和失败回调函数。
function MyPromise(executor) {
var self = this;
self.state = 'pending';
self.value = undefined;
self.reason = undefined;
self.onFulfilledCallbacks = [];
self.onRejectedCallbacks = [];
function resolve(value) {
if (self.state === 'pending') {
self.state = 'fulfilled';
self.value = value;
self.onFulfilledCallbacks.forEach(function(callback) {
callback(self.value);
});
}
}
function reject(reason) {
if (self.state === 'pending') {
self.state = 'rejected';
self.reason = reason;
self.onRejectedCallbacks.forEach(function(callback) {
callback(self.reason);
});
}
}
try {
executor
(resolve, reject);
} catch (e) {
reject(e);
}
}
MyPromise.prototype.then = function(onFulfilled, onRejected) {
var self = this;
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function(value) { return value; };
onRejected = typeof onRejected === 'function' ? onRejected : function(reason) { throw reason; };
var newPromise = new MyPromise(function(resolve, reject) {
// TODO: 实现 then 办法的其余部分
});
return newPromise;
};
步骤 5: 解决 Promise 状态转换和回调执行
咱们须要在 then 办法中解决 Promise 的状态转换和回调的执行。依据以后 Promise 的状态,咱们能够立刻执行回调函数或将回调函数增加到相应的回调数组中。
MyPromise.prototype.then = function(onFulfilled, onRejected) {
var self = this;
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function(value) { return value; };
onRejected = typeof onRejected === 'function' ? onRejected : function(reason) { throw reason; };
var newPromise = new MyPromise(function(resolve, reject) {
function handleFulfilled(value) {
try {
var x = onFulfilled(value);
resolvePromise(newPromise, x, resolve, reject);
} catch (e) {
reject(e);
}
}
function handleRejected(reason) {
try {
var x = onRejected(reason);
resolvePromise(newPromise, x, resolve, reject);
} catch (e) {
reject(e);
}
}
if (self.state === 'fulfilled') {
setTimeout(function() {
handleFulfilled(self.value);
}, 0);
} else if (self.state === 'rejected') {
setTimeout(function() {
handleRejected(self.reason);
}, 0);
} else if (self.state === 'pending') {
self.onFulfilledCallbacks.push(function(value) {
setTimeout(function() {
handleFulfilled(value);
}, 0);
});
self.onRejectedCallbacks.push(function(reason) {
setTimeout(function() {
handleRejected(reason);
}, 0);
});
}
});
return newPromise;
};
步骤 6: 解析 Promise
最初,咱们须要实现 resolvePromise 函数,用于解析 Promise。它会解决 thenable 和非 thenable 值,并依据其状态执行相应的解决。
function resolvePromise(promise, x, resolve, reject) {
if (promise === x) {
reject(new TypeError('Circular reference detected.'));
}
if (x && typeof x === 'object' || typeof x === 'function') {
var called = false;
try {
var then = x.then;
if (typeof then === 'function') {
then.call(
x,
function(y) {
if (!called) {
called = true;
resolvePromise(promise, y, resolve, reject);
}
},
function(r) {
if (!called) {
called = true;
reject(r);
}
}
);
} else {
resolve(x);
}
} catch (e) {
if (!called) {
called = true;
reject(e);
}
}
} else {
resolve(x);
}
}
Promise的测试与调试
1. 装置Jest:
确保在我的项目中装置了Jest。能够应用npm或yarn进行装置。
npm install jest --save-dev
2. 编写单元测试:
在我的项目中创立一个测试文件,以.test.js
为后缀,编写单元测试用例来验证Promise的各个性能和办法的正确性。例如,能够编写测试用例来验证状态转换、回调函数的执行、链式调用等方面的行为是否合乎预期。
// promise.test.js
const { MyPromise } = require('./promise');
describe('MyPromise', () => {
it('should fulfill with correct value', () => {
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('success');
}, 100);
});
return promise.then((value) => {
expect(value).toBe('success');
});
});
it('should reject with correct reason', () => {
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
reject(new Error('failure'));
}, 100);
});
return promise.catch((reason) => {
expect(reason).toBeInstanceOf(Error);
expect(reason.message).toBe('failure');
});
});
// 更多测试用例...
});
3. 运行测试:
应用Jest运行编写的测试用例,执行Promise的测试。
npx jest
4. 模仿异步操作:
应用setTimeout
函数或Promise.resolve
等办法来模仿异步操作,并确保Promise在正确的机会进行状态转换和回调函数的执行。例如,能够应用setTimeout
来模仿异步操作的实现。
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('success');
}, 100);
});
promise.then((value) => {
console.log(value); // 输入: success
});
5. 调试Promise链:
在开发过程中,可能会遇到Promise链上的问题,如回调函数不执行、后果不合乎预期等。能够应用console.log
或debugger
语句来打印两头变量的值,或者应用Jest的调试性能来逐渐跟踪Promise链的执行过程。
const promise1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('success');
}, 100);
});
const promise2 = promise1.then((value) => {
console.log(value); // 输入: success
return value.toUpperCase();
});
promise2.then((value) => {
console.log(value); // 输入: SUCCESS
});
能够应用Jest的--inspect
参数进行调试,或者在代码中增加debugger
语句来触发断点。
npx jest --inspect
应用Promise/A+测试套件
应用Promise/A+测试套件是确保Promise实现符合规范的重要步骤。Promise/A+测试套件是一组针对Promise实现的测试用例,可用于验证Promise是否合乎Promise/A+标准的要求。
以下是应用Promise/A+测试套件的步骤:
- 下载Promise/A+测试套件:
首先,从Promise/A+官网的GitHub仓库(https://github.com/promises-aplus/promises-tests)下载Promise/A+测试套件的代码。将其保留到我的项目的测试目录中。 - 集成测试套件:
将Promise/A+测试套件集成到我的项目的测试环境中,确保能够运行测试套件并取得后果。 - 实现Promise接口:
依据Promise/A+标准的要求,实现一个符合规范的Promise类。确保Promise类的行为和接口与标准统一。 - 运行测试套件:
应用测试框架(如Mocha、Jest等)运行Promise/A+测试套件。在测试套件的配置中,指定测试文件为Promise/A+测试套件的入口文件。 - 验证后果:
查看测试套件的运行后果。如果所有的测试用例都通过,示意Promise实现合乎Promise/A+标准。如果有测试用例失败,依据测试后果来调试和修复Promise实现中的问题。
上面是一个示例,展现如何应用Promise/A+测试套件进行测试:
// 装置Promise/A+测试套件
npm install promises-aplus-tests --save-dev
// 集成Promise/A+测试套件到测试环境中
const promisesAplusTests = require('promises-aplus-tests');
const { MyPromise } = require('./promise');
// 运行Promise/A+测试套件
promisesAplusTests(MyPromise, function (err) {
// 测试实现后的回调函数
if (err) {
console.error('Promise/A+测试失败:', err);
} else {
console.log('Promise/A+测试通过!');
}
});
在上述代码中,MyPromise
是本人实现的Promise类。通过将MyPromise
传递给promisesAplusTests
函数,将Promise类集成到Promise/A+测试套件中。运行测试后,将会失去测试后果。
通过应用Promise/A+测试套件,能够验证本人实现的Promise是否合乎Promise/A+标准的要求,确保Promise的行为和接口的一致性。
Promise其它API
要实现Promise.all
和Promise.race
等其余API,能够依据Promise的标准和性能需要来编写相应的代码。以下是对这两个API的实现进行开展解说的代码示例:
- 实现
Promise.all
:Promise.all
办法接管一个可迭代对象(如数组或类数组对象),并返回一个新的Promise,该Promise在所有输出的Promise都胜利实现时才会胜利,否则将会失败。返回的Promise的解决值是一个由所有输出Promise解决值组成的数组。
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
const results = [];
let completedCount = 0;
const checkCompletion = () => {
if (completedCount === promises.length) {
resolve(results);
}
};
for (let i = 0; i < promises.length; i++) {
promises[i]
.then((value) => {
results[i] = value;
completedCount++;
checkCompletion();
})
.catch((reason) => {
reject(reason);
});
}
if (promises.length === 0) {
resolve(results);
}
});
};
应用示例:
const promise1 = new Promise((resolve) => setTimeout(() => resolve(1), 1000));
const promise2 = new Promise((resolve) => setTimeout(() => resolve(2), 2000));
const promise3 = new Promise((resolve) => setTimeout(() => resolve(3), 1500));
Promise.all([promise1, promise2, promise3])
.then((results) => {
console.log(results); // 输入: [1, 2, 3]
})
.catch((reason) => {
console.error(reason);
});
- 实现
Promise.race
:Promise.race
办法接管一个可迭代对象(如数组或类数组对象),并返回一个新的Promise,该Promise将与最先解决或回绝的输出Promise具备雷同的状态。
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i]
.then((value) => {
resolve(value);
})
.catch((reason) => {
reject(reason);
});
}
});
};
应用示例:
const promise1 = new Promise((resolve) => setTimeout(() => resolve(1), 1000));
const promise2 = new Promise((resolve) => setTimeout(() => resolve(2), 2000));
const promise3 = new Promise((resolve) => setTimeout(() => resolve(3), 1500));
Promise.race([promise1, promise2, promise3])
.then((value) => {
console.log(value); // 输入: 1
})
.catch((reason) => {
console.error(reason);
});
参考资料
- Promise/A+ 标准官网文档:https://promisesaplus.com/
发表回复