ฉันจะกำหนดค่าสภาพแวดล้อมที่แตกต่างใน Angular.js ได้อย่างไร


220

คุณจะจัดการตัวแปร / ค่าคงที่สำหรับสภาพแวดล้อมที่แตกต่างกันได้อย่างไร

นี่อาจเป็นตัวอย่าง:

API ส่วนที่เหลือของฉันคือสามารถเข้าถึงได้ในlocalhost:7080/myapi/แต่เพื่อนของฉันที่ทำงานในรหัสเดียวกันภายใต้การควบคุมเวอร์ชัน Git มี API จะนำไปใช้ใน Tomcat localhost:8099/hisapi/ของเขาใน

สมมติว่าเรามีสิ่งนี้:

angular
    .module('app', ['ngResource'])

    .constant('API_END_POINT','<local_end_point>')

    .factory('User', function($resource, API_END_POINT) {
        return $resource(API_END_POINT + 'user');
    });

ฉันจะฉีดค่าปลายทางที่ถูกต้องของ API แบบไดนามิกได้อย่างไรขึ้นอยู่กับสภาพแวดล้อม

ใน PHP ฉันมักจะทำสิ่งนี้กับconfig.username.xmlไฟล์การรวมไฟล์การกำหนดค่าพื้นฐาน (config.xml) กับไฟล์การกำหนดค่าสภาพแวดล้อมท้องถิ่นที่รู้จักโดยชื่อของผู้ใช้ แต่ฉันไม่รู้วิธีจัดการสิ่งนี้ใน JavaScript?

คำตอบ:


209

ฉันสายไปเล็กน้อย แต่ถ้าคุณกำลังใช้Gruntฉันก็ประสบความสำเร็จgrunt-ng-constantอย่างมาก

ส่วนกำหนดค่าสำหรับngconstantในGruntfile.jsดูเหมือนของฉัน

ngconstant: {
  options: {
    name: 'config',
    wrap: '"use strict";\n\n{%= __ngModule %}',
    space: '  '
  },
  development: {
    options: {
      dest: '<%= yeoman.app %>/scripts/config.js'
    },
    constants: {
      ENV: 'development'
    }
  },
  production: {
    options: {
      dest: '<%= yeoman.dist %>/scripts/config.js'
    },
    constants: {
      ENV: 'production'
    }
  }
}

งานที่ใช้ngconstantดูเหมือน

grunt.registerTask('server', function (target) {
  if (target === 'dist') {
    return grunt.task.run([
      'build',
      'open',
      'connect:dist:keepalive'
    ]);
  }

  grunt.task.run([
    'clean:server',
    'ngconstant:development',
    'concurrent:server',
    'connect:livereload',
    'open',
    'watch'
  ]);
});

grunt.registerTask('build', [
  'clean:dist',
  'ngconstant:production',
  'useminPrepare',
  'concurrent:dist',
  'concat',
  'copy',
  'cdnify',
  'ngmin',
  'cssmin',
  'uglify',
  'rev',
  'usemin'
]);

ดังนั้นการรันgrunt serverจะสร้างconfig.jsไฟล์ในapp/scripts/ลักษณะที่ปรากฏ

"use strict";
angular.module("config", []).constant("ENV", "development");

ในที่สุดฉันประกาศการพึ่งพาโมดูลที่ต้องการ:

// the 'config' dependency is generated via grunt
var app = angular.module('myApp', [ 'config' ]);

ตอนนี้ค่าคงที่ของฉันสามารถถูกฉีดพึ่งพาได้เมื่อจำเป็น เช่น,

app.controller('MyController', ['ENV', function( ENV ) {
  if( ENV === 'production' ) {
    ...
  }
}]);

10
แทนที่จะวาง'ngconstant:development'ใน'serve'- ถ้าคุณวางไว้ในการตั้งค่านาฬิกาภายใต้การ'gruntfile'เป็นtasks: ['ngconstant:development']- คุณจะไม่ต้องเริ่มต้นใหม่grunt serveเมื่อคุณปรับปรุงตัวแปรพัฒนาใน gruntfile
จ่ายตั้งแต่

10
แทนที่จะเพิ่มค่าคงที่ของคุณใน gruntfile.js คุณสามารถใส่ไฟล์แยกดังนี้:package: grunt.file.readJSON('development.json')
Guilhem Soulas

3
มีไวยากรณ์ปรับปรุงสำหรับ Gruntfile.js ในรุ่น 0.5 ของเสียงฮึดฮัด-ng คงเป็น: github.com/werk85/grunt-ng-constant/issues/31 คำตอบที่ดีขอบคุณ!
pherris

10
สำหรับผู้ที่ใช้อึกมีอึก-ng คงที่
Dheeraj Vepakomma

4
ฉันได้พบมันยังจำเป็นต้องรวมไฟล์สคริปต์ / config.js ไปที่มุมเพื่อหาโมดูลเช่นนี้: <script src = "สคริปต์ / config.js"> </script>
Toni Gamez

75

โซลูชันที่ยอดเยี่ยมอย่างหนึ่งอาจแยกค่าเฉพาะสภาพแวดล้อมทั้งหมดออกเป็นโมดูลเชิงมุมแยกบางตัวซึ่งโมดูลอื่นทั้งหมดขึ้นอยู่กับ:

angular.module('configuration', [])
       .constant('API_END_POINT','123456')
       .constant('HOST','localhost');

จากนั้นโมดูลของคุณที่ต้องการรายการเหล่านั้นสามารถประกาศการพึ่งพาได้:

angular.module('services',['configuration'])
       .factory('User',['$resource','API_END_POINT'],function($resource,API_END_POINT){
           return $resource(API_END_POINT + 'user');
       });

ตอนนี้คุณสามารถคิดถึงสิ่งดีๆเพิ่มเติมได้:

โมดูลที่มีการกำหนดค่าสามารถแยกออกเป็น configuration.js ซึ่งจะรวมอยู่ในหน้าของคุณ

คุณทุกคนสามารถแก้ไขสคริปต์นี้ได้อย่างง่ายดายตราบใดที่คุณไม่ได้ตรวจสอบไฟล์แยกนี้เป็น git แต่จะง่ายกว่าหากไม่เช็คอินการกำหนดค่าหากอยู่ในไฟล์แยกต่างหาก นอกจากนี้คุณยังสามารถแยกสาขาในพื้นที่ได้

ตอนนี้ถ้าคุณมีระบบการสร้างเช่น ANT หรือ Maven ขั้นตอนต่อไปของคุณอาจใช้ตัวยึดตำแหน่งสำหรับค่า API_END_POINT ซึ่งจะถูกแทนที่ในระหว่างการสร้างด้วยค่าเฉพาะของคุณ

หรือคุณมีของคุณconfiguration_a.jsและconfiguration_b.jsตัดสินใจที่แบ็กเอนด์ที่จะรวม


30

สำหรับอึกผู้ใช้อึก-ng คงยังเป็นประโยชน์รวมกับอึก-concat , เหตุการณ์สตรีมและyargs

var concat = require('gulp-concat'),
    es = require('event-stream'),
    gulp = require('gulp'),
    ngConstant = require('gulp-ng-constant'),
    argv = require('yargs').argv;

var enviroment = argv.env || 'development';

gulp.task('config', function () {
  var config = gulp.src('config/' + enviroment + '.json')
    .pipe(ngConstant({name: 'app.config'}));
  var scripts = gulp.src('js/*');
  return es.merge(config, scripts)
    .pipe(concat('app.js'))
    .pipe(gulp.dest('app/dist'))
    .on('error', function() { });
});

ในโฟลเดอร์ปรับแต่งของฉันฉันมีไฟล์เหล่านี้:

ls -l config
total 8
-rw-r--r--+ 1 .. ci.json
-rw-r--r--+ 1 .. development.json
-rw-r--r--+ 1 .. production.json

จากนั้นคุณสามารถเรียกใช้gulp config --env developmentและจะสร้างสิ่งนี้:

angular.module("app.config", [])
.constant("foo", "bar")
.constant("ngConstant", true);

ฉันมีสเป็คนี้ด้วย:

beforeEach(module('app'));

it('loads the config', inject(function(config) {
  expect(config).toBeTruthy();
}));

มีวิธีลบอาร์เรย์อ้างอิงด้วยค่าคงอึก ng หรือไม่ ฉันไม่มีการพึ่งพาค่าคงที่ของฉันเหมือนที่คุณมีในสิ่งนี้เช่น "ngAnimate" ถ้าฉันไม่รวมมันฉันจะได้รับอาร์เรย์ที่ว่างเปล่าเป็น angular.module ("my.module.config", []) แต่ฉันต้องการผลลัพธ์เป็น angular.module ("my.module.config") ฉันไม่เห็นตัวเลือกใด ๆ ในค่าคงที่ gulp ng แต่ฉันเห็นว่าคุณสามารถผ่าน deps: false ในแพ็คเกจคงที่ grunt ng ความช่วยเหลือใด ๆ
Arun Gopalpuri

17

เพื่อให้บรรลุตามนั้นฉันแนะนำให้คุณใช้ AngularJS Environment plugin: https://www.npmjs.com/package/angular-environment

นี่คือตัวอย่าง:

angular.module('yourApp', ['environment']).
config(function(envServiceProvider) {
    // set the domains and variables for each environment 
    envServiceProvider.config({
        domains: {
            development: ['localhost', 'dev.local'],
            production: ['acme.com', 'acme.net', 'acme.org']
            // anotherStage: ['domain1', 'domain2'], 
            // anotherStage: ['domain1', 'domain2'] 
        },
        vars: {
            development: {
                apiUrl: '//localhost/api',
                staticUrl: '//localhost/static'
                // antoherCustomVar: 'lorem', 
                // antoherCustomVar: 'ipsum' 
            },
            production: {
                apiUrl: '//api.acme.com/v2',
                staticUrl: '//static.acme.com'
                // antoherCustomVar: 'lorem', 
                // antoherCustomVar: 'ipsum' 
            }
            // anotherStage: { 
            //  customVar: 'lorem', 
            //  customVar: 'ipsum' 
            // } 
        }
    });

    // run the environment check, so the comprobation is made 
    // before controllers and services are built 
    envServiceProvider.check();
});

จากนั้นคุณสามารถเรียกตัวแปรจากคอนโทรลเลอร์ของคุณเช่นนี้

envService.read('apiUrl');

หวังว่ามันจะช่วย


1
เขาสลับไปมาระหว่างการพัฒนาและการผลิตได้อย่างไร
Mawg กล่าวว่านำสถานะโมนิก้ากลับมาอีกครั้งใน

สวัสดี Juan Pablo หรือ @Mawg ถ้าคุณคิดออก ก่อนที่ฉันจะถามคำถามเกี่ยวกับ SO / แจ้งปัญหาเกี่ยวกับ Github; วิธีการที่ไม่angular-environmentตรวจสอบสภาพแวดล้อมหรือไม่? คือสิ่งที่คุณต้องทำในเครื่อง / เว็บเซิร์ฟเวอร์ของคุณเพื่อให้มันรู้ว่ามันเป็น dev / prod ตามลำดับ?
StevieP

กำลังอ่านเอกสารอีกครั้ง ... " envServiceProvider.check()... จะตั้งค่าสภาพแวดล้อมที่เหมาะสมโดยอัตโนมัติตามโดเมนที่กำหนด" ดังนั้นฉันจึงคิดว่ามันตรวจจับโดเมนปัจจุบันและกำหนดสภาพแวดล้อมให้เหมาะสม - เวลาทดสอบ!
StevieP

13

คุณสามารถใช้lvh.me:9000เพื่อเข้าถึงแอป AngularJS ของคุณ ( lvh.meเพียงชี้ไปที่ 127.0.0.1) จากนั้นระบุปลายทางอื่นหากlvh.meเป็นโฮสต์:

app.service("Configuration", function() {
  if (window.location.host.match(/lvh\.me/)) {
    return this.API = 'http://localhost\\:7080/myapi/';
  } else {
    return this.API = 'http://localhost\\:8099/hisapi/';
  }
});

จากนั้นฉีดบริการกำหนดค่าและใช้Configuration.APIทุกที่ที่คุณต้องการเข้าถึง API:

$resource(Configuration.API + '/endpoint/:id', {
  id: '@id'
});

ตาด clunky แต่ทำงานได้ดีสำหรับฉันแม้ว่าในสถานการณ์ที่แตกต่างกันเล็กน้อย (จุดสิ้นสุดของ API แตกต่างกันในการผลิตและการพัฒนา)


1
ดังนั้นฉันคิดว่าบ่อยครั้งที่ผู้คนมีสิ่งที่ซับซ้อนมากเกินไป การใช้งานง่าย ๆwindow.location.hostก็เพียงพอแล้วสำหรับฉัน
joseym

7

เราสามารถทำอะไรแบบนี้ได้

(function(){
    'use strict';

    angular.module('app').service('env', function env() {

        var _environments = {
            local: {
                host: 'localhost:3000',
                config: {
                    apiroot: 'http://localhost:3000'
                }
            },
            dev: {
                host: 'dev.com',
                config: {
                    apiroot: 'http://localhost:3000'
                }
            },
            test: {
                host: 'test.com',
                config: {
                    apiroot: 'http://localhost:3000'
                }
            },
            stage: {
                host: 'stage.com',
                config: {
                apiroot: 'staging'
                }
            },
            prod: {
                host: 'production.com',
                config: {
                    apiroot: 'production'
                }
            }
        },
        _environment;

        return {
            getEnvironment: function(){
                var host = window.location.host;
                if(_environment){
                    return _environment;
                }

                for(var environment in _environments){
                    if(typeof _environments[environment].host && _environments[environment].host == host){
                        _environment = environment;
                        return _environment;
                    }
                }

                return null;
            },
            get: function(property){
                return _environments[this.getEnvironment()].config[property];
            }
        }

    });

})();

และในของคุณcontroller/serviceเราสามารถฉีดการพึ่งพาและเรียกวิธีการรับกับคุณสมบัติที่จะเข้าถึง

(function() {
    'use strict';

    angular.module('app').service('apiService', apiService);

    apiService.$inject = ['configurations', '$q', '$http', 'env'];

    function apiService(config, $q, $http, env) {

        var service = {};
        /* **********APIs **************** */
        service.get = function() {
            return $http.get(env.get('apiroot') + '/api/yourservice');
        };

        return service;
    }

})();

$http.get(env.get('apiroot') จะคืนค่า URL ตามสภาพแวดล้อมโฮสต์


5

คำถามที่ดี!

ทางออกหนึ่งคือการใช้ไฟล์ config.xml ของคุณต่อไปและให้ข้อมูลจุดปลาย api จากแบ็กเอนด์ไปยัง html ที่คุณสร้างขึ้นเช่นนี้ (ตัวอย่างใน php):

<script type="text/javascript">
angular.module('YourApp').constant('API_END_POINT', '<?php echo $apiEndPointFromBackend; ?>');
</script>

อาจไม่ใช่วิธีแก้ปัญหาที่สวย แต่มันใช้งานได้

โซลูชันอื่นอาจรักษาAPI_END_POINTค่าคงที่ตามที่ควรจะเป็นในการผลิตและแก้ไขไฟล์โฮสต์ของคุณให้ชี้ URL นั้นไปยัง API ท้องถิ่นของคุณแทน

หรืออาจเป็นวิธีแก้ปัญหาที่ใช้localStorageสำหรับการแทนที่เช่นนี้

.factory('User',['$resource','API_END_POINT'],function($resource,API_END_POINT){
   var myApi = localStorage.get('myLocalApiOverride');
   return $resource((myApi || API_END_POINT) + 'user');
});

สวัสดี joimbimbeng ฉันเขียนวิธีแก้ปัญหาที่ฉันใช้ใน php เพื่ออธิบายประเด็น เราพยายามที่จะเขียนโค้ดไคลเอนต์จาวาสคริปต์ที่บริสุทธิ์ด้วยแบ็กเอนด์ RESTful java ที่บริสุทธิ์ดังนั้น php / js จึงไม่ใช่กรณีของฉันและเมื่อฉันเขียนใน php ฉันพยายามทำให้ php และ js ไม่ผสมกันเสมอ แต่ขอบคุณสำหรับคำตอบ ฉันคิดว่าวิธีการแก้ปัญหา @kfis สามารถใช้งานได้: ไฟล์ configuration.js ไม่อยู่ภายใต้การควบคุมเวอร์ชันที่มีโมดูลการกำหนดค่า ด้วยวิธีนี้ฉันสามารถฉีด / โหลดนอกจากนี้ยังมีโมดูลการกำหนดค่าที่แตกต่างกันสำหรับวัตถุประสงค์ในการทดสอบหากจำเป็น ขอบคุณเพื่อน.
rbarilani

@ hal9087 ฉันเห็นด้วยอย่างสมบูรณ์เกี่ยวกับส่วนของภาษาผสมควรหลีกเลี่ยงค่าใช้จ่ายทั้งหมด :) ฉันชอบโซลูชันการกำหนดค่าเช่นกันฉันจะระลึกไว้เสมอเมื่อฉันต้องการสิ่งที่คล้ายกัน!
joakimbeng

4

ดึกมากถึงเธรด แต่เทคนิคที่ฉันใช้ pre-Angular คือการใช้ประโยชน์จาก JSON และความยืดหยุ่นของ JS ในการอ้างอิงคีย์การรวบรวมแบบไดนามิกและใช้ข้อเท็จจริงที่ไม่สามารถเปลี่ยนแปลงได้ของสภาพแวดล้อม (ชื่อโฮสต์เซิร์ฟเวอร์ภาษาเบราว์เซอร์ปัจจุบัน เป็นต้น) เป็นอินพุตเพื่อเลือกแบ่งแยก / ต้องการชื่อคีย์ต่อท้ายภายในโครงสร้างข้อมูล JSON

สิ่งนี้ไม่เพียง แต่นำไปใช้กับบริบทของสภาพแวดล้อม (ต่อ OP) แต่บริบทใด ๆ (เช่นภาษา) เพื่อให้ i18n หรือความแปรปรวนอื่น ๆ ที่จำเป็นพร้อมกันและ (ในอุดมคติ) ภายในรายการการกำหนดค่าเดียวโดยไม่ต้องทำซ้ำ

ในประมาณ 10 LINES VANILLA JS

ตัวอย่างที่เรียบง่าย แต่สุดคลาสสิก: URL ปลายทางของ API ปลายทางในไฟล์คุณสมบัติที่จัดรูปแบบ JSON ซึ่งแตกต่างกันไปตามสภาพแวดล้อมที่ (natch) เซิร์ฟเวอร์โฮสต์จะแตกต่างกัน:

    ...
    'svcs': {
        'VER': '2.3',
        'API@localhost': 'http://localhost:9090/',
        'API@www.uat.productionwebsite.com': 'https://www.uat.productionwebsite.com:9090/res/',
        'API@www.productionwebsite.com': 'https://www.productionwebsite.com:9090/api/res/'
    },
    ...

กุญแจสำคัญในฟังก์ชั่นการเลือกปฏิบัติเป็นเพียงชื่อโฮสต์ของเซิร์ฟเวอร์ในคำขอ

โดยปกติสามารถรวมกับคีย์เพิ่มเติมตามการตั้งค่าภาษาของผู้ใช้:

    ...
    'app': {
        'NAME': 'Ferry Reservations',
        'NAME@fr': 'Réservations de ferry',
        'NAME@de': 'Fähren Reservierungen'
    },
    ...

ขอบเขตของการเลือกปฏิบัติ / การกำหนดค่าตามความชอบสามารถถูก จำกัด อยู่ที่แต่ละคีย์ (ตามด้านบน) โดยที่คีย์ "base" จะถูกเขียนทับเฉพาะในกรณีที่มีคีย์ + ต่อท้ายที่ตรงกันสำหรับอินพุตไปยังฟังก์ชัน - หรือโครงสร้างทั้งหมดและโครงสร้างนั้นเอง แยกวิเคราะห์ซ้ำสำหรับการเลือก / การต่อท้ายการกำหนดลักษณะที่ตรงกัน:

    'help': {
        'BLURB': 'This pre-production environment is not supported. Contact Development Team with questions.',
        'PHONE': '808-867-5309',
        'EMAIL': 'coder.jen@lostnumber.com'
    },
    'help@www.productionwebsite.com': {
        'BLURB': 'Please contact Customer Service Center',
        'BLURB@fr': 'S\'il vous plaît communiquer avec notre Centre de service à la clientèle',
        'BLURB@de': 'Bitte kontaktieren Sie unseren Kundendienst!!1!',
        'PHONE': '1-800-CUS-TOMR',
        'EMAIL': 'customer.service@productionwebsite.com'
    },

ดังนั้นหากผู้ใช้ที่เข้าชมเว็บไซต์การผลิตมีการตั้งค่าภาษาเยอรมัน ( de ) การตั้งค่าด้านบนจะยุบไปที่:

    'help': {
        'BLURB': 'Bitte kontaktieren Sie unseren Kundendienst!!1!',
        'PHONE': '1-800-CUS-TOMR',
        'EMAIL': 'customer.service@productionwebsite.com'
    },

ฟังก์ชั่นการตั้งค่า / การเลือกปฏิบัติที่มีมนต์ขลังเช่นไรฟังก์ชั่นการเขียนใหม่ของ JSON มีลักษณะอย่างไร ไม่มาก:

// prefer(object,suffix|[suffixes]) by/par/durch storsoc
// prefer({ a: 'apple', a@env: 'banana', b: 'carrot' },'env') -> { a: 'banana', b: 'carrot' }
function prefer(o,sufs) {
    for (var key in o) {
        if (!o.hasOwnProperty(key)) continue; // skip non-instance props
        if(key.split('@')[1]) { // suffixed!
            // replace root prop with the suffixed prop if among prefs
            if(o[key] && sufs.indexOf(key.split('@')[1]) > -1) o[key.split('@')[0]] = JSON.parse(JSON.stringify(o[key]));

            // and nuke the suffixed prop to tidy up
            delete o[key];

            // continue with root key ...
            key = key.split('@')[0];
        }

        // ... in case it's a collection itself, recurse it!
        if(o[key] && typeof o[key] === 'object') prefer(o[key],sufs);

    };
};

ในการใช้งานของเราซึ่งรวมถึงเว็บไซต์ Angular และ pre-Angular เราเพียงแค่บูตการกำหนดค่าไว้ล่วงหน้าก่อนการเรียกทรัพยากรอื่น ๆ โดยการวาง JSON ภายในการปิด JS ที่ดำเนินการด้วยตนเองรวมถึงฟังก์ชัน prefer () และคุณสมบัติพื้นฐานของชื่อโฮสต์และ รหัสภาษา (และยอมรับคำต่อท้ายเพิ่มเติมใด ๆ ที่คุณอาจต้องการ):

(function(prefs){ var props = {
    'svcs': {
        'VER': '2.3',
        'API@localhost': 'http://localhost:9090/',
        'API@www.uat.productionwebsite.com': 'https://www.uat.productionwebsite.com:9090/res/',
        'API@www.productionwebsite.com': 'https://www.productionwebsite.com:9090/api/res/'
    },
    ...
    /* yadda yadda moar JSON und bisque */

    function prefer(o,sufs) {
        // body of prefer function, broken for e.g.
    };

    // convert string and comma-separated-string to array .. and process it
    prefs = [].concat( ( prefs.split ? prefs.split(',') : prefs ) || []);
    prefer(props,prefs);
    window.app_props = JSON.parse(JSON.stringify(props));
})([location.hostname, ((window.navigator.userLanguage || window.navigator.language).split('-')[0])  ] );

ไซต์มุมฉากตอนนี้จะมีหน้าต่างที่ยุบ (ไม่มีคีย์ @ ต่อท้าย) หน้าต่าง app_propsเพื่ออ้างถึง

ไซต์ Angular เป็นขั้นตอน bootstrap / init เพียงแค่คัดลอกวัตถุอุปกรณ์ประกอบฉากที่หล่นลงไปใน $ rootScope และ (ทางเลือก) ทำลายมันจากขอบเขตทั่วโลก / หน้าต่าง

app.constant('props',angular.copy(window.app_props || {})).run( function ($rootScope,props) { $rootScope.props = props; delete window.app_props;} );

จะถูกฉีดเข้าไปในคอนโทรลเลอร์ในภายหลัง:

app.controller('CtrlApp',function($log,props){ ... } );

หรือถูกอ้างถึงจากการโยงในมุมมอง:

<span>{{ props.help.blurb }} {{ props.help.email }}</span>

เตือน? อักขระ @ ไม่ใช่การตั้งชื่อตัวแปร / คีย์ JS / JSON ที่ถูกต้อง แต่ได้รับการยอมรับแล้ว หากเป็นการดีลเลอร์ให้เปลี่ยนการประชุมที่คุณชอบเช่น "__" (ขีดล่างคู่) ตราบใดที่คุณยังยึดติดอยู่

เทคนิคนี้สามารถนำไปใช้กับฝั่งเซิร์ฟเวอร์ซึ่งเชื่อมต่อกับ Java หรือ C # แต่ประสิทธิภาพ / ความกะทัดรัดของคุณอาจแตกต่างกันไป

อีกทางหนึ่งฟังก์ชั่น / การประชุมอาจเป็นส่วนหนึ่งของสคริปต์คอมไพล์ส่วนหน้าของคุณเพื่อให้ JSON เต็มทุกสภาพแวดล้อม / ภาษาทั้งหมดเต็มไปด้วยอารมณ์ไม่เคยส่งผ่านสาย

UPDATE

เราได้พัฒนาการใช้เทคนิคนี้เพื่ออนุญาตให้มีคำต่อท้ายหลายรายการเพื่อหลีกเลี่ยงการถูกบังคับให้ใช้คอลเลกชัน (คุณยังสามารถทำได้ตามที่คุณต้องการ) และเพื่อให้เป็นไปตามลำดับของคำต่อท้ายที่ต้องการ

ตัวอย่าง (ดูที่การทำงานjsFiddle ):

var o = { 'a':'apple', 'a@dev':'apple-dev', 'a@fr':'pomme',
          'b':'banana', 'b@fr':'banane', 'b@dev&fr':'banane-dev',
          'c':{ 'o':'c-dot-oh', 'o@fr':'c-point-oh' }, 'c@dev': { 'o':'c-dot-oh-dev', 'o@fr':'c-point-oh-dev' } };

/*1*/ prefer(o,'dev');        // { a:'apple-dev', b:'banana',     c:{o:'c-dot-oh-dev'}   }
/*2*/ prefer(o,'fr');         // { a:'pomme',     b:'banane',     c:{o:'c-point-oh'}     }
/*3*/ prefer(o,'dev,fr');     // { a:'apple-dev', b:'banane-dev', c:{o:'c-point-oh-dev'} }
/*4*/ prefer(o,['fr','dev']); // { a:'pomme',     b:'banane-dev', c:{o:'c-point-oh-dev'} }
/*5*/ prefer(o);              // { a:'apple',     b:'banana',     c:{o:'c-dot-oh'}       }

1/2 (การใช้งานพื้นฐาน) ชอบคีย์ '@dev' ทิ้งกุญแจอื่น ๆ ที่ต่อท้ายทั้งหมด

3ชอบ '@dev' มากกว่า '@fr', ชอบ '@ dev & fr' มากกว่าคนอื่น ๆ ทั้งหมด

4 (เหมือนกับ 3 แต่ชอบ '@fr' มากกว่า '@dev')

5ไม่มีคำต่อท้ายที่ต้องการลดลงคุณสมบัติต่อท้ายทั้งหมด

มันทำได้โดยการให้คะแนนแต่ละคุณสมบัติที่ต่อท้ายและส่งเสริมมูลค่าของคุณสมบัติที่ต่อท้ายกับคุณสมบัติที่ไม่ได้ต่อท้ายเมื่อวนซ้ำคุณสมบัติและค้นหาส่วนต่อท้ายที่มีคะแนนสูงกว่า

ประสิทธิภาพบางอย่างในเวอร์ชันนี้รวมถึงการลบการพึ่งพา JSON ไปเป็นแบบถ่ายสำเนาลึกและเรียกใช้เฉพาะวัตถุที่อยู่รอดในรอบการให้คะแนนที่ระดับความลึก:

function prefer(obj,suf) {
    function pr(o,s) {
        for (var p in o) {
            if (!o.hasOwnProperty(p) || !p.split('@')[1] || p.split('@@')[1] ) continue; // ignore: proto-prop OR not-suffixed OR temp prop score
            var b = p.split('@')[0]; // base prop name
            if(!!!o['@@'+b]) o['@@'+b] = 0; // +score placeholder
            var ps = p.split('@')[1].split('&'); // array of property suffixes
            var sc = 0; var v = 0; // reset (running)score and value
            while(ps.length) {
                // suffix value: index(of found suffix in prefs)^10
                v = Math.floor(Math.pow(10,s.indexOf(ps.pop())));
                if(!v) { sc = 0; break; } // found suf NOT in prefs, zero score (delete later)
                sc += v;
            }
            if(sc > o['@@'+b]) { o['@@'+b] = sc; o[b] = o[p]; } // hi-score! promote to base prop
            delete o[p];
        }
        for (var p in o) if(p.split('@@')[1]) delete o[p]; // remove scores
        for (var p in o) if(typeof o[p] === 'object') pr(o[p],s); // recurse surviving objs
    }
    if( typeof obj !== 'object' ) return; // validate
    suf = ( (suf || suf === 0 ) && ( suf.length || suf === parseFloat(suf) ) ? suf.toString().split(',') : []); // array|string|number|comma-separated-string -> array-of-strings
    pr(obj,suf.reverse());
}


-8

คุณเคยเห็นคำถามนี้และคำตอบหรือไม่

คุณสามารถตั้งค่าที่ใช้ได้ทั่วโลกสำหรับแอพของคุณเช่นนี้:

app.value('key', 'value');

และใช้ในบริการของคุณ คุณสามารถย้ายรหัสนี้ไปยังไฟล์ config.js และดำเนินการกับการโหลดหน้าเว็บหรือช่วงเวลาที่สะดวกอื่น


7
มีใครช่วยอธิบายหน่อยได้ไหมว่าทำไมนี่ถึงเป็นคำตอบที่ไม่ดี มันถูก downvoted อย่างหนาแน่น แต่ไม่ได้แสดงความคิดเห็นเดียว ...
aendrew

5
นี่มันเก่าแก่แล้ว แต่ถ้าฉันต้องเดาว่าทำไม downvotes นั่นเป็นเพราะมันไม่ได้แก้ปัญหาของการกำหนดค่าเฉพาะของสภาพแวดล้อมมันเป็นเพียงข้อเสนอแนะที่จะใช้. value () เพื่อตั้งค่าทั่วโลกในแอปเก่า ๆ ไม่มีการพูดถึงว่าจะใช้สิ่งนี้ได้อย่างไรโดยขึ้นอยู่กับ env หรืออะไรก็ตามตามพารามิเตอร์คำถามดั้งเดิม
coblr
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.