pomelo 소스 분석(3) - 설정 및 읽기 및 app.load

8525 단어
작성자:[email protected], 전재
다음을 수행합니다.https://github.com/NetEase/chatofpomelo/tree/master/game-server서버는 예를 들어 읽기 설정이 어떻게 완성되었는지 설명하고chatofpomelo는pomelo를 채팅 서버로 하는 예이다.그것의 입구점은 앱이다.js.코드 내용은 다음과 같습니다.
var pomelo = require('pomelo');
var routeUtil = require('./app/util/routeUtil');
/**
 * Init app for client.
 */
var app = pomelo.createApp();
//        
app.set('name', 'chatofpomelo'); 


// app configure
app.configure('production|development', function() {
    // route configures
    app.route('chat', routeUtil.chat);
//            
    app.set('connectorConfig', {
        connector: pomelo.connectors.sioconnector,
        // 'websocket', 'polling-xhr', 'polling-jsonp', 'polling'
        transports: ['websocket', 'polling'],
        heartbeats: true,
        closeTimeout: 60 * 1000,
        heartbeatTimeout: 60 * 1000,
        heartbeatInterval: 25 * 1000
    });
    // filter configures
    app.filter(pomelo.timeout());
});

// start app
app.start();

//         
process.on('uncaughtException', function(err) {
    console.error(' Caught exception: ' + err.stack);
});

코드에서 볼 때 모두 앱을 통해 보입니다.set 추가 설정 - 이것은 Pomelo가 비교적 다른 부분입니다. 흔히 볼 수 있는 설정은 여러 개의 파일로 나뉘어진include 방식으로 한 파일에 집중됩니다.아니면 서류가 하나밖에 없거나.그러나 Pomelo의 설정은 흩어져서 이것저것 어울릴 수 있다.app.set 이 함수의 정의는 응용 프로그램에 있습니다.js의 내용은 다음과 같다.
/**
 * Assign `setting` to `val`, or return `setting`'s value.
 *
 * Example:
 *
 *  app.set('key1', 'value1');
 *  app.get('key1');  // 'value1'
 *  app.key1;         // undefined
 *
 *  app.set('key2', 'value2', true);
 *  app.get('key2');  // 'value2'
 *  app.key2;         // 'value2'
 *
 * @param {String} setting the setting of application
 * @param {String} val the setting's value
 * @param {Boolean} attach whether attach the settings to application
 * @return {Server|Mixed} for chaining, or the setting value
 * @memberOf Application
 */
Application.set = function (setting, val, attach) {
  if (arguments.length === 1) {
    return this.settings[setting];
  }
  this.settings[setting] = val;
  if(attach) {
    this[setting] = val;
  }
  return this;
};


이 함수의 주석은 매우 상세하게 썼다. 내가 앞에서 방금 분석한 c 코드에 비해 그 코드는 기본적으로 주석이 없다.코드에서 알 수 있듯이 실제로는settings에 설정을 추가했다.settings의 초기화는 settings={}입니다. 즉, 처음에는 빈 대상입니다.
여기에 설정된 설정은 분석이 끝났고pomelo는 이렇게 간단하고 직접적이다.설정된 키는 connectorConfig이고value는 js 대상입니다.다음은 그것이 어디에서 읽혔는지 살펴보자.그것은 틀림없이 Application에 있을 것이다.start에서 읽은 거예요.

/**
 * Start application. It would load the default components and start all the loaded components.
 *
 * @param  {Function} cb callback function
 * @memberOf Application
 */
 Application.start = function(cb) {
  this.startTime = Date.now();
  if(this.state > STATE_INITED) {
    utils.invokeCallback(cb, new Error('application has already start.'));
    return;
  }
  
  var self = this;
  appUtil.startByType(self, function() { //   startByType
    appUtil.loadDefaultComponents(self); //  startByType      
    var startUp = function() {
      appUtil.optComponents(self.loaded, Constants.RESERVED.START, function(err) {
        self.state = STATE_START;
        if(err) {
          utils.invokeCallback(cb, err);
        } else {
          logger.info('%j enter after start...', self.getServerId());
          self.afterStart(cb);
        }
      });
    };
    var beforeFun = self.lifecycleCbs[Constants.LIFECYCLE.BEFORE_STARTUP];
    if(!!beforeFun) {
      beforeFun.call(null, self, startUp);
    } else {
      startUp();
    }
  });
};

appUtil.startByType 이 편은 언급하지 않고 바로 리셋을 보았습니다. 리셋의 첫 번째 줄은 바로 appUtil입니다.loadDefaultComponents, 이 함수는 설정을 읽습니다.그러나 이 함수는 매우 좋지 않은 행동을 한다. 바로 문자의 상수는 기본적으로 하드코딩이다. 즉, 모두가 흔히 말하는 코드에 죽도록 쓴다.코드를 보지 않으면 아무도 이 설정을 모르면 반드시 이 이름을 불러야 한다.

/**
 * Load default components for application.
 */
module.exports.loadDefaultComponents = function(app) {
  var pomelo = require('../pomelo');
  // load system default components
  if (app.serverType === Constants.RESERVED.MASTER) {
    app.load(pomelo.master, app.get('masterConfig'));
  } else {
    app.load(pomelo.proxy, app.get('proxyConfig'));
    if (app.getCurServer().port) {
      app.load(pomelo.remote, app.get('remoteConfig'));
    }
    if (app.isFrontend()) {
      app.load(pomelo.connection, app.get('connectionConfig')); 
//   ,       
      app.load(pomelo.connector, app.get('connectorConfig'));
      app.load(pomelo.session, app.get('sessionConfig'));
      // compatible for schedulerConfig
      if(app.get('schedulerConfig')) {
        app.load(pomelo.pushScheduler, app.get('schedulerConfig'));
      } else {
        app.load(pomelo.pushScheduler, app.get('pushSchedulerConfig'));
      }
    }
    app.load(pomelo.backendSession, app.get('backendSessionConfig'));
    app.load(pomelo.channel, app.get('channelConfig'));
    app.load(pomelo.server, app.get('serverConfig'));
  }
  app.load(pomelo.monitor, app.get('monitorConfig'));
};

분석은 아직 끝나지 않았다. 설정이 읽히는 것만 분석했고 읽은 후의 행동은 아직 분석되지 않았기 때문이다.그러니까 이 배치는 도대체 뭘 하는 데 쓰이는 거야?바로 앱을 보셔야 합니다.로드야.app.load의 첫 번째 매개 변수는pomelo입니다.connector, 이 물건은 실제로는 __defineGetter__로 함수의 봉인을 한 번 했는데, 실제로는 함수이다.__defineGetter__ 표준 안에 있는 게 아니에요.
/**
 * Load component
 *
 * @param  {String} name    (optional) name of the component
 * @param  {Object} component component instance or factory function of the component
 * @param  {[type]} opts    (optional) construct parameters for the factory function
 * @return {Object}     app instance for chain invoke
 * @memberOf Application
 */
Application.load = function(name, component, opts) {
  if(typeof name !== 'string') { //name   
    opts = component;  //    
    component = name; //    
    name = null;
    if(typeof component.name === 'string') {
      name = component.name;
    }
  }

  if(typeof component === 'function') { //   component   
    component = component(this, opts);
  }

  if(!name && typeof component.name === 'string') {
    name = component.name;
  }

  if(name && this.components[name]) {
    // ignore duplicat component
    logger.warn('ignore duplicate component: %j', name);
    return;
  }

  this.loaded.push(component);
  if(name) {
    // components with a name would get by name throught app.components later.
    this.components[name] = component;
  }

  return this;
};

그래서load라는 함수에서name가 들어오는 것은 실제 함수이고 이 함수를 호출하여opts를 매개 변수로 들어간다.이렇게 하면 모듈의 적재를 실현하였다.
팝업으로.connector는 예를 들어 모듈을 불러오는 과정을 설명합니다. 위에서pomelo를 설명했습니다.connector는 실제로 함수입니다. 이것은 어떻게 실현됩니까?우선 Pomelo로 가세요.js에서 검색하면 찾을 수 없을 거야.connector의.아래 몇 줄의 코드를 통해 추가되었기 때문이다.components 디렉터리에 connector라는 파일이 있습니다.js
/**
 * Auto-load bundled components with getters.
 */
fs.readdirSync(__dirname + '/components').forEach(function (filename) {
  if (!/\.js$/.test(filename)) {
    return;
  }
//  connector.js,  connector
  var name = path.basename(filename, '.js'); 
//  bind    
  var _load = load.bind(null, './components/', name);
  
  Pomelo.components.__defineGetter__(name, _load);
//   ,__defineGetter__   ,   pomelo.getter   ,
// _load  
  Pomelo.__defineGetter__(name, _load);
});

코드에서 볼 수 있듯이 Pomelo가 된다.connector가 방문되었을 때 하나 호출됩니다load 함수.
다음은 이 로드 함수가 무엇을 했는지 다시 한 번 볼까요?load 함수는 실제적으로 Require, 마운트 모듈을 실행했습니다.
function load(path, name) {
  if (name) {
    return require(path + name);
  }
  return require(path);
}


하지만load는요, load예요.bind의 결과.실제로는 this 바늘을null로 설정했습니다.bind에 대한 설명:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
여기 있는 Require는 함수를 되돌려주고, Require ('connector ') 는 함수를 되돌려줍니다.코드를 보십시오,conpoment/connector.js에 한 마디가 있어요.
module.exports = function(app, opts) {
  return new Component(app, opts);
};

이 함수야말로 앱이다.load가 진정으로 호출하는 함수, 즉pomelo.connector가 되돌아오는 값, 즉 Require가 되돌아오는 값입니다.
그래서 app.load(pomelo.connector, app.get('connectorConfig')); 이 행 코드는 실제로component/connector 모듈을 불러오고 모듈 exports의 함수를 실행하여 설정을 전송하여component를 만듭니다.이 과정은 이미 매우 상세하게 말했기 때문에 관중들이 이해할 수 있을지 없을지는 말할 수 없다.

좋은 웹페이지 즐겨찾기