普通视图

发现新文章,点击刷新页面。
昨天 — 2026年3月30日首页

发布为一个 npm 包

2026年3月30日 18:29

太棒了!👏
你已经从“理解 Promise”走到了“创造可用工具”的阶段。

现在,我们来手把手带你把 MyPromise 发布到 npm ——
完成一次 从学习 → 实践 → 分享 的完整闭环!


包名示例:@yourname/mypromisemypromise-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 账号(如果还没有)

访问:www.npmjs.com/signup

然后在终端登录:

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-learnsimple-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"
}

📌 注意:


🔐 第六步:发布到 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 写文档

❤️ 最后一句话

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

你现在不只是在学代码,
而是在向世界分享你的理解与创造。

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


❌
❌