Как вызвать функцию вне функции вызова отправленного события

#javascript #node.js

#javascript #node.js

Вопрос:

Я прошу прощения, если это неясно, уже поздно, и я не знаю, как лучше всего это объяснить.

Я использую источник события для передачи данных из ответа сервера в функцию внутри отдельного класса в другом файле, но при попытке использовать методы в этих классах this ключевое слово, очевидно, не работает (потому что в этом сценарии this ссылается на источник события сервера) — как бы я ссылался на функцию внутри самого класса? Я предоставил код, который поможет немного лучше проиллюстрировать мою точку зрения

ServiceClass.js

 class StreamService {
  /**
     *
     * @param {} database
     * @param {Collection<Guild>} guilds
  */
  constructor (database, guilds,) {
      .....
      twitchListener.on('live', this.sendLiveAlert) // fire test method when we get a notification
      // if there are streamers to monitor, being monitoring
      winston.info('Stream service initialized')
  }

  ..............

  async get (url, params = null, headers = this.defaultHeaders) {
    // check oauth token
    const expirationDate = this.token.expires_in || 0
    if (expirationDate <= Date.now() || !this.token) await this.getAccessToken()
    // build URL
    const index = 0
    let paramsString = ''
    for (const [key, value] of params.entries()) {
      if (index === 0) {
        paramsString  = `?${key}=${value}`
      } else {
        paramsString  = `amp;${key}=${value}`
      }
    }
    const res = await fetch(url   paramsString, { method: 'GET', headers: headers })
    if (!res.ok) {
      winston.error(`Error performing GET request to ${url}`)
      return null
    }
    return await res.json()
  }

  async sendLiveAlert(streamTitle, streamURL, avatar, userName, gameId, viewerCount, thumbnail, startDateTime) {
    // get game name first (no headers needed)
    const params = new Map()
    params.set('id', gameId)
    const gameData = await this.get('https://api.twitch.tv/heliix/games', params, this.defaultHeaders)
    if(gameData) {
      // get webhook and send message to channel
      const webhookClient = new WebhookClient('755641606555697305', 'OWZvI01kUUf4AAIR9uv2z4CxRse3Ik8b0LKOluaOYKmhE33h0ypMLT0JJm3laomlZ05o')
      const embed = new MessageEmbed()
        .setTitle(`${userName} just went live on Twitch!`)
        .setURL(streamURL)
        .setThumbnail(avatar)
        .addFields(
          { name: 'Now Playing', value: gameData.data[0].name },
          { name: 'Stream Title', value: streamTitle }
        )
        .setImage(thumbnail)
    }
    webhookClient.send('Webhook test', embed)
  }
}
  

Server.js

 class TwitchWebhookListener extends EventEmitter {
    ......................
    // Routes
    server
      .post((req, res) => {
        console.log('Incoming POST request on /webhooks')
              ............................
                const data = req.body.data[0]
                if(!this.streamerLiveStatus.get(data.user_id) amp;amp; data.type === 'live') {
                  // pass request body to bot for processing
                  this.emit(
                    'live',
                    data.title, // stream title
                    `https://twitch.tv/${data.user_name}`, // channel link
                    `https://avatar.glue-bot.xyz/twitch/${data.user_name}`, // streamer avatar
                    data.user_name,
                    data.game_id,
                    data.viewer_count,
                    data.thumbnail_url,
                    data.started_at // do we need this?
                  )
                }
                break
              default:
                res.send(`Unknown webhook for ${req.params.id}`)
                break
            }
          } else {
            console.log('The Signature did not match')
            res.send('Ok')
          }
        } else {
          console.log('It didn't seem to be a Twitch Hook')
          res.send('Ok')
        }
      })
  }
}

const listener = new TwitchWebhookListener()
listener.listen()

module.exports = listener
  

В sendLiveAlert методе я пытаюсь вызвать метод get класса StreamService — но поскольку он вызывается непосредственно через эмиттер внутри server.js , this относится конкретно к Server.js классу — есть ли какой-либо способ, который я могу использовать StreamService.get() ? Очевидно, я мог бы просто переписать код внутри самого метода, но это кажется ненужным, когда он прямо там?

Ответ №1:

Измените это:

 twitchListener.on('live', this.sendLiveAlert)
  

к этому:

 twitchListener.on('live', this.sendLiveAlert.bind(this))
  

Или вы также могли бы сделать это:

 twitchListener.on('live', (...args) => {
    this.sendLiveAlert(...args);
});
  

С помощью .bind() этого создается оболочка функции, которая сбрасывает правильное значение this для вас. В случае функции arrow она сохраняет лексическое значение this для вас.

Комментарии:

1. Одновременные ответы. Я мог бы удалить свою, если вы обработаете args в своей функции второго варианта.

2. @RahulBhobe — Я добавил аргументы.

3. Это мое воображение или поля между блоками кода и текстом в ответах внезапно увеличились?

4. А, понятно! Я думал, что это проблема с областью видимости, я просто не был уверен, как с этим справиться. Это сработало как шарм!