发布为一个 npm 包

太棒了!👏

你已经从"理解 Promise"走到了"创造可用工具"的阶段。

现在,我们来手把手带你把 MyPromise 发布到 npm ------

完成一次 从学习 → 实践 → 分享 的完整闭环!


包名示例:@yourname/mypromisemypromise-learn

功能:

javascript 复制代码
import MyPromise from 'mypromise-learn';

new MyPromise(resolve => resolve('Hello')).then(console.log);

✅ 第一步:准备工作

1. 安装 Node.js 和 npm

确保你已安装:

bash 复制代码
node -v   # 应输出 v14.x 以上
npm -v    # 应输出 6.x 以上

👉 下载地址:nodejs.org


2. 注册 npm 账号(如果还没有)

访问:www.npmjs.com/signup

然后在终端登录:

bash 复制代码
npm login
# 输入你的用户名、密码、邮箱

✅ 登录成功后就可以发布包了。


📁 第二步:创建项目目录结构

bash 复制代码
mkdir mypromise-npm
cd mypromise-npm
npm init -y

生成的 package.json 长这样:

bash 复制代码
{
  "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-learnsimple-promise 等。


📄 第三步:添加源码文件

创建 index.js

ini 复制代码
// 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 测试文件:

ini 复制代码
// 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(关键配置)

perl 复制代码
{
  "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"
}

📌 注意:


🔐 第六步:发布到 npm

复制代码
npm publish

✅ 成功后你会看到:

css 复制代码
+ mypromise-learn@1.0.0

🎉 恭喜!你的包已经上线!

访问:https://www.npmjs.com/package/mypromise-learn 查看页面。


🌐 第七步:别人怎么使用它?

安装:

复制代码
npm install mypromise-learn

使用:

javascript 复制代码
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 写文档

❤️ 最后一句话

你已经完成了从"学习者"到"贡献者"的转变。

你现在不只是在学代码,

而是在向世界分享你的理解与创造。

这比任何面试题都更有价值。✨


相关推荐
树上有只程序猿2 小时前
低代码何时能出个“秦始皇”一统天下?我是真学不动啦!
前端·后端·低代码
TT_哲哲2 小时前
小程序双模式(文件 / 照片)上传组件封装与解析
前端·javascript
菜果果儿2 小时前
Vue 3 + TypeScript 常用代码示例总结
前端
前端付豪2 小时前
实现多角色模式切换
前端·架构
从文处安2 小时前
「九九八十一难」从回调地狱到异步秩序:深入理解 JavaScript Promise
前端·javascript
要换昵称了2 小时前
Axios二次封装及API 调用框架
前端·vue.js
进击的尘埃3 小时前
Node.js 子进程管理:child_process 模块的正确打开方式
javascript
猫腻前端3 小时前
深度图d3绘制交互逻辑
前端
搞个锤子哟3 小时前
el-popover气泡宽度由内容撑起
前端