You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js:如何在类方法的异步函数中访问this?

解决异步回调中无法访问类实例this的问题

这个问题我之前也碰到过,核心原因是异步回调函数会改变this的指向——默认情况下,回调里的this指向的是调用回调的上下文(也就是PersonModel.find内部的执行上下文),而不是你的personRepository实例。你试过bind(this)但没生效,应该是绑定的位置不对,咱们一步步来解决:


方法1:使用箭头函数(最简洁的现代方案)

箭头函数不会绑定自己的this,它会继承外层作用域的this,直接把回调改成箭头函数就能解决问题:

var PersonModel = require('./model')

class PersonRepository {
  constructor() {
    this._persons = new Set();
  }

  getAll(cb) {
    let results = new Set();
    // 把回调函数改成箭头函数
    PersonModel.find({}, 'firstName lastName', (err, people) => {
      if (err) {
        console.error(err);
        return cb(err); // 注意原代码里的next(err)应该是cb(err),因为参数是cb
      }
      people.forEach((person) => {
        results.add(person);
      });
      this._persons.add("this._persons 现在可以访问了!");
      cb(this._persons);
    });
    this._persons.add("this._persons is accessible");
    console.log(this);
  }
}

// 测试
var personRepo = new PersonRepository();
personRepo.getAll((persons) => {
  for (let item of persons) console.log(item);
});

方法2:提前保存this到变量(兼容旧环境)

如果你的运行环境不支持箭头函数,可以在回调外部把当前实例的this存成变量(比如self或that),然后在回调里用这个变量访问:

getAll(cb) {
  let results = new Set();
  const self = this; // 保存当前实例的this
  PersonModel.find({}, 'firstName lastName', function (err, people) {
    if (err) {
      console.error(err);
      return cb(err);
    }
    people.forEach((person) => {
      results.add(person);
    });
    self._persons.add("通过self访问到实例属性了");
    cb(self._persons);
  });
  // ...其他代码
}

方法3:正确使用bind(修正你之前的用法)

你之前用PersonModel.find.bind(this)是把find方法的this绑定了,但回调函数的this还是没改。应该给回调函数本身绑定this:

getAll(cb) {
  let results = new Set();
  PersonModel.find({}, 'firstName lastName', function (err, people) {
    if (err) {
      console.error(err);
      return cb(err);
    }
    people.forEach((person) => {
      results.add(person);
    });
    this._persons.add("绑定后能访问实例属性了");
    cb(this._persons);
  }.bind(this)); // 给回调函数绑定当前实例的this
  // ...其他代码
}

方法4:用async/await重构(更优雅的异步写法)

如果你的环境支持ES6+的async/await,可以把回调风格的代码改成Promise风格,彻底避免this指向问题,代码可读性也更高:

class PersonRepository {
  constructor() {
    this._persons = new Set();
  }

  // 改成async函数
  async getAll() {
    try {
      // 把find方法转成Promise(Mongoose的find默认支持exec()返回Promise)
      const people = await PersonModel.find({}, 'firstName lastName').exec();
      let results = new Set();
      people.forEach((person) => {
        results.add(person);
      });
      this._persons.add("async/await下this正常访问");
      return this._persons; // 直接返回结果
    } catch (err) {
      console.error(err);
      throw err; // 抛出错误让调用者处理
    }
  }
}

// 调用方式
var personRepo = new PersonRepository();
personRepo.getAll().then((persons) => {
  for (let item of persons) console.log(item);
}).catch(err => console.error(err));

// 或者在async函数里用await:
// async function test() {
//   try {
//     const persons = await personRepo.getAll();
//     for (let item of persons) console.log(item);
//   } catch (err) {
//     console.error(err);
//   }
// }
// test();

内容的提问来源于stack exchange,提问作者b_it_s

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:36:41