发布为一个 npm 包
2026年3月30日 18:29
太棒了!👏
你已经从“理解 Promise”走到了“创造可用工具”的阶段。
现在,我们来手把手带你把 MyPromise 发布到 npm ——
完成一次 从学习 → 实践 → 分享 的完整闭环!
包名示例:@yourname/mypromise 或 mypromise-learn
功能:
import MyPromise from 'mypromise-learn';
new MyPromise(resolve => resolve('Hello')).then(console.log);
✅ 第一步:准备工作
1. 安装 Node.js 和 npm
确保你已安装:
node -v # 应输出 v14.x 以上
npm -v # 应输出 6.x 以上
👉 下载地址:nodejs.org
2. 注册 npm 账号(如果还没有)
然后在终端登录:
npm login
# 输入你的用户名、密码、邮箱
✅ 登录成功后就可以发布包了。
📁 第二步:创建项目目录结构
mkdir mypromise-npm
cd mypromise-npm
npm init -y
生成的 package.json 长这样:
{
"name": "mypromise-learn",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"keywords": ["promise", "tutorial", "async"],
"author": "Your Name",
"license": "MIT"
}
💡 建议名字别叫 mypromise,容易和别人冲突。可以用 mypromise-learn、simple-promise 等。
📄 第三步:添加源码文件
创建 index.js:
// index.js
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
this.onFulfilledCallbacks.forEach(fn => fn());
}
};
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
}
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err; };
const promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
const x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
} else if (this.status === PENDING) {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
}
});
return promise2;
}
resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected'));
}
let called = false;
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
const then = x.then;
if (typeof then === 'function') {
then.call(x,
y => {
if (called) return;
called = true;
this.resolvePromise(promise2, y, resolve, reject);
},
r => {
if (called) return;
called = true;
reject(r);
}
);
} else {
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}
catch(onRejected) {
return this.then(null, onRejected);
}
static resolve(value) {
return new MyPromise(resolve => resolve(value));
}
static reject(reason) {
return new MyPromise((_, reject) => reject(reason));
}
static all(promises) {
return new MyPromise((resolve, reject) => {
const results = [];
let count = 0;
if (promises.length === 0) return resolve(results);
promises.forEach((p, index) => {
MyPromise.resolve(p).then(
value => {
results[index] = value;
count++;
if (count === promises.length) resolve(results);
},
reject
);
});
});
}
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach(p => {
MyPromise.resolve(p).then(resolve, reject);
});
});
}
}
module.exports = MyPromise;
⚠️ 如果你用的是 ES6 模块语法(import/export),需要改为 export default MyPromise 并设置 "type": "module",后面会说明。
🧪 第四步:本地测试一下
创建 test.js 测试文件:
// test.js
const MyPromise = require('./index');
console.log('开始测试 MyPromise...');
MyPromise.resolve(1)
.then(res => res + 1)
.then(res => {
console.log('结果:', res); // 输出: 结果: 2
return MyPromise.resolve(3);
})
.then(console.log) // 输出: 3
.catch(console.error);
// 测试循环引用
const p = MyPromise.resolve(1);
const p2 = p.then(() => p2);
p2.catch(err => console.log('捕获循环引用:', err.message));
运行测试:
node test.js
✅ 如果输出正常,说明可以发布了!
📦 第五步:完善 package.json(关键配置)
{
"name": "mypromise-learn",
"version": "1.0.0",
"description": "A hand-written Promise implementation for learning purposes.",
"main": "index.js",
"scripts": {
"test": "node test.js"
},
"keywords": ["promise", "tutorial", "async", "javascript"],
"author": "Your Name <you@email.com>",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/yourname/mypromise.git"
},
"bugs": {
"url": "https://github.com/yourname/mypromise/issues"
},
"homepage": "https://github.com/yourname/mypromise#readme"
}
📌 注意:
-
name必须全局唯一 - 可以先查是否已被占用:www.npmjs.com/search
🔐 第六步:发布到 npm
npm publish
✅ 成功后你会看到:
+ mypromise-learn@1.0.0
🎉 恭喜!你的包已经上线!
访问:https://www.npmjs.com/package/mypromise-learn 查看页面。
🌐 第七步:别人怎么使用它?
安装:
npm install mypromise-learn
使用:
const MyPromise = require('mypromise-learn');
// 或 ES6 import(需支持 module)
import MyPromise from 'mypromise-learn';
🎁 进阶建议(让项目更专业)
| 功能 | 方法 |
|---|---|
| 📄 添加 README.md | 写清楚用途、API、示例 |
| 🧩 支持 ESM | 加 "type": "module" 并导出 .mjs 文件 |
| 🧪 单元测试 | 用 Jest 写测试用例 |
| 🔄 自动发布 | 用 GitHub Actions 实现 CI/CD |
| 📘 文档站点 | 用 VitePress 写文档 |
❤️ 最后一句话
你已经完成了从“学习者”到“贡献者”的转变。
你现在不只是在学代码,
而是在向世界分享你的理解与创造。
这比任何面试题都更有价值。✨