Метод объекта может быть вызван в функции, когда функция вызывается сама по себе, но когда функция вызывается через setTimeout, объект не определен - PullRequest
0 голосов
/ 09 февраля 2019

У меня есть следующий класс Conference:

//UrlSerializer is for encoding JSON objects into GET url
const UrlSerializer=require('./urlSerializer');

class Conference{

    constructor(client,workspace){
        this.client=client;
        this.workspace=workspace;
        this.urlSerializer=new UrlSerializer();
    }


    announce(conferenceSid,timeRemaining){
        var parameters={
            timeRemaining:timeRemaining
        }
        var url=this.urlSerializer.serialize('conferenceAnnounceTime',parameters);
        console.log("conference.announce url: "+url);
        this.client.conferences(conferenceSid)
            .update({
                announceUrl:url,
                announceMethod:'GET'
            })
            .then(conference=>console.log(conference.friendlyName));
    }

    setTimedAnnounce(initialMinutes,minutesToElapse,conferenceSid){
        var minutesRemaining=initialMinutes-minutesToElapse;
        setTimeout(this.announce,minutesToElapse*60000,minutesRemaining);
    }

}

module.exports=Conference;

UrlSerializer is:

const querystring=require('querystring');
require('env2')('.env');

class UrlSerializer{

    constructor(){
        this.paramArrayName="parameters";
    }

    serialize(endpoint,paramArray){
        var url=process.env.APP_BASE_URL+"/"+endpoint;
        console.log("urlSerializer base url: "+url);
        var arrayString=JSON.stringify(paramArray);
        console.log("urlSerializer stringified parameter array: "+arrayString);
        var fullUrl=url+"?"+querystring.stringify({[this.paramArrayName]:arrayString});
        console.log("urlSerializer full url: "+fullUrl);
        return fullUrl;
    }   
}

module.exports=UrlSerializer;

Я вызываю conference функции из конечной точки Express в другом модуле server, следующим образом:

app.get('/conferenceEvents',function(req,res){
    conferenceSid=req.query.ConferenceSid;
    conference.announce(conferenceSid,initialMinutes);
    conference.setTimedAnnounce(initialMinutes,0.25,conferenceSid);
    res.type('application/json');
    res.status(200).send();
});

Вызов на conference.announce завершается успешно с выводом на консоль:

urlSerializer base url: http://x.ngrok.io/conferenceAnnounceTime
urlSerializer stringified parameter array: {"timeRemaining":5}
urlSerializer full url: http://x.ngrok.io/conferenceAnnounceTime?parameters=%7B%22timeRemaining%22%3A5%7D
conference.announce url: http://x.ngrok.io/conferenceAnnounceTime?parameters=%7B%22timeRemaining%22%3A5%7D

Но по истечении 15 секунд после вызова conference.setTimedAnnounce() я получаю следующееошибка:

TypeError: Cannot read property 'serialize' of undefined
    at Timeout.announce [as _onTimeout] (c:\thisAppPath\conference.js:45:30)
    at ontimeout (timers.js:502:15)
    at tryOnTimeout (timers.js:323:5)
    at Timer.listOnTimeout (timers.js:290:5)

Я думаю, может быть, когда таймер вызывает announce, он делает это так, что экземпляр urlSerializer находится вне области видимости.Как заставить его распознавать urlSerializer, когда announce вызывается через setTimeout()?

РЕДАКТИРОВАТЬ: Я попытался сохранить область this следующим образом:

    setTimedAnnounce(initialMinutes,minutesToElapse,conferenceSid){
        var that=this;
        var minutesRemaining=initialMinutes-minutesToElapse;
        setTimeout(that.announce,minutesToElapse*60000,minutesRemaining);
    }

, но этотолько что выдал мне ту же ошибку.

РЕДАКТИРОВАТЬ 2:

Я использовал решение Barmar this.announce.bind(this), и это разрешило TypeError, но массив параметров и URL не были правильно созданы вsetTimeout () вызов объявления;вывод на консоль выглядит следующим образом:

urlSerializer base url: http://x.ngrok.io/conferenceAnnounceTime
urlSerializer stringified parameter array: {}
urlSerializer full url: http://x.ngrok.io/conferenceAnnounceTime?parameters=%7B%7D
conference.announce url: http://x.ngrok.io/conferenceAnnounceTime?parameters=%7B%7D

Я подозреваю, что есть где-то еще, что мне нужно использовать .bind(this), чтобы urlSerializer.serialize() вызывали с this в нужной области, но я неотследил его еще.

РЕДАКТИРОВАТЬ 3:

Неважно, я понял - setTimeout нужно было передать conferenceSid в качестве аргумента, а также minutesRemaining.Работаю сейчас.

1 Ответ

0 голосов
/ 09 февраля 2019
    setTimeout(this.announce,minutesToElapse*60000,minutesRemaining);

должно быть

    setTimeout(this.announce.bind(this),minutesToElapse*60000,minutesRemaining);

Передача свойства функции в качестве аргумента не связывает контекст this.Он связывается автоматически только при вызове метода с этим синтаксисом.

...