Прокси и их преимущества

внешний интерфейс JavaScript

Перевод: Лю Сяоси

Оригинальная ссылка:Dev induct.com/blog post/36…

Другие статьи можно нажать: GitHub.com/Иветт Л.А. Ю/Б…

Что такое прокси

Обычно, когда мы говорим о языке JavaScript, мы говорим о новых возможностях, предоставляемых стандартом ES6, и эта статья не стала исключением. Мы обсудим прокси-серверы JavaScript и то, что они делают, но прежде чем мы углубимся в это, давайте посмотрим, что такое определение прокси-сервера.

Определение в MDN таково: прокси-объект — это пользовательское поведение, используемое для определения основных операций (например, поиск свойств, присвоение, перечисление, вызов функции и т. д.).

Другими словами, мы можем сказать, что прокси-объект — это оболочка вокруг нашего целевого объекта, где мы можем манипулировать его свойствами и предотвращать прямой доступ к нему. Вам может быть трудно применить их к реальному коду, я рекомендую вам внимательно прочитать концепцию, это может изменить вашу точку зрения.

период, термин

handler

Объект-заполнитель, содержащий ловушки.

traps

Методы, обеспечивающие доступ к свойствам. Это похоже на концепцию ловушек в операционных системах.

target

Прокси виртуализированные объекты. (фактический объект, обернутый и управляемый прокси-объектом)

В этой статье я будуgetа такжеsetПодводные камни предоставляют простые варианты использования, учитывая, что в конце мы увидим, как их использовать, и включим более сложные функции, такие как API.

Синтаксис и варианты использования

let p = new Proxy(target, handler);

Передайте цель и обработчикProxyконструктор, который создает прокси-объект. Теперь давайте посмотрим, как этим воспользоваться. Чтобы более четко увидеть преимущества Proxy, во-первых, нам нужно написать код без него.

Представьте, что у нас есть пользовательский объект с несколькими свойствами, мы хотим напечатать информацию о пользователе, если свойство существует, и создать исключение, если оно не существует. Когда прокси-объект не используется, код для оценки того, существует ли значение атрибута, также помещается в функцию, которая печатает информацию о пользователе, т. е.printUserin (это не то, что нам нужно), как показано в следующей демонстрации:

let user = {
    name: 'John',
    surname: 'Doe'
};

let printUser = (property) => {
    let value = user[property];
    if (!value) {
        throw new Error(`The property [${property}] does not exist`);
    } else {
        console.log(`The user ${property} is ${value}`);
    }
}

printUser('name'); // 输出: 'The user name is John'
printUser('email'); // 抛出错误: The property [email] does not exist

get

Взглянув на приведенный выше код, вы обнаружите, что: переместите условие и исключение в другое место, в то время какprintUserБыло бы лучше просто сосредоточиться на фактической логике отображения информации о пользователе. Здесь мы можем использовать прокси-объекты, давайте обновим этот пример.

let user = {
    name: 'John',
    surname: 'Doe'
};

let proxy = new Proxy(user, {
    get(target, property) {
        let value = target[property];
        if (!value) {
            throw new Error(`The property [${property}] does not exist`);
        }
        return value;
    }
});

let printUser = (property) => {
    console.log(`The user ${property} is ${proxy[property]}`);
};

printUser('name'); // 输出: 'The user name is John'
printUser('email'); // 抛出错误: The property [email] does not exist

В приведенном выше примере мы обернулиuserобъект и устанавливаетgetметод. Этот метод действует как перехватчик, перед возвратом значения сначала проверяется значение свойства, и выбрасывается исключение, если оно не существует.

Результат такой же, как и в первом случае, но на этот разprintUserФункция фокусируется на логике и обрабатывает только сообщение.

set

Другой пример прокси, который может быть полезен, — это проверка значения атрибута. В этом случае нам нужно использоватьsetметод и проверьте в нем. Это очень полезный хук, когда, например, нам нужно обеспечить целевой тип. Давайте посмотрим на фактическое использование:

let user = new Proxy({}, {
    set(target, property, value) {
        if (property === 'name' && Object.prototype.toString.call(value) !== '[object String]') { // 确保是 string 类型
            throw new Error(`The value for [${property}] must be a string`);
        };
        target[property] = value;
    }
});

user.name = 1; // 抛出错误: The value for [name] must be a string

Это довольно простые случаи использования, когда прокси может пригодиться:

  • формат
  • модификаторы значения и типа
  • привязка данных
  • отладка
  • ...

Теперь пришло время создать более сложный корпус использования.

API с прокси — более сложный пример

Используя знания из простого варианта использования, мы можем создать оболочку API для использования в нашем приложении. В настоящее время поддерживается толькоgetа такжеpostзапроса, но его можно легко расширить. Код показан ниже.

const api = new Proxy({}, {
    get(target, key, context) {
        return target[key] || ['get', 'post'].reduce((acc, key) => {
            acc[key] = (config, data) => {

                if (!config && !config.url || config.url === '') throw new Error('Url cannot be empty.');
                let isPost = key === 'post';

                if (isPost && !data) throw new Error('Please provide data in JSON format when using POST request.');

                config.headers = isPost ? Object.assign(config.headers || {}, { 'content-type': 'application/json;chartset=utf8' }) :
                    config.headers;

                return new Promise((resolve, reject) => {
                    let xhr = new XMLHttpRequest();
                    xhr.open(key, config.url);
                    if (config.headers) {
                        Object.keys(config.headers).forEach((header) => {
                            xhr.setRequestHeader(header, config.headers[header]);
                        });
                    }
                    xhr.onload = () => (xhr.status === 200 ? resolve : reject)(xhr);
                    xhr.onerror = () => reject(xhr);
                    xhr.send(isPost ? JSON.stringify(data) : null);
                });
            };
            return acc;
        }, target)[key];
    },
    set() {
        throw new Error('API methods are readonly');
    },
    deleteProperty() {
        throw new Error('API methods cannot be deleted!');
    }
});

Объясним простую реализацию,setа такжеdeleteProperty. Мы добавили уровень защиты, чтобы гарантировать, что всякий раз, когда кто-то случайно или непреднамеренно попытается установить новые значения для любого свойства API, возникнет исключение.

Вызывается каждый раз, когда вы пытаетесь удалить свойствоdeletePropertyметод. Можно гарантировать, что никто не сможет удалить какие-либо свойства из нашего прокси (например, здесь API), потому что обычно мы не хотим терять методы API.

getЗдесь интересно, он делает несколько вещей.targetпустой объект,getметод будет использоваться в первый раз, когда кто-тоapiсоздать все методы (например, текущийgetа такжеpostпросьба), вreduceВ обратном вызове мы выполняем проверки и проверки, требуемые спецификацией API, в соответствии с предоставленной конфигурацией. В этом примере мы не разрешаем пустые URL-адреса и размещать запросы без предоставления данных. Эти проверки могут быть расширены и изменены, но важно то, что мы можем сосредоточиться только на этом одном месте.

reduceвыполняется только при первом вызове API, после чего весьreduceобработать,getБудет выполнено только поведение по умолчанию, и будет возвращено значение свойства, которое является обработчиком API. Каждый обработчик возвращает объект Promise, отвечающий за создание запроса и вызов службы.

использовать:

api.get({
    url: 'my-url'
}).then((xhr) => {
    alert('Success');
}, (xhr) => {
    alert('Fail');
});
delete api.get; //throw new Error('API methods cannot be deleted!'); 

В заключение

Прокси могут пригодиться, когда вам нужен больший контроль над вашими данными. Вы можете расширить или запретить доступ к необработанным данным на основе контролируемых правил для мониторинга объектов и обеспечения правильного поведения.

Если вам понравилась эта статья, подпишитесь на мой официальный аккаунт. Не стесняйтесь выражать свои мысли в разделе комментариев ниже.

Спасибо за вашу готовность потратить свое драгоценное время на чтение этой статьи. Если эта статья дала вам небольшую помощь или вдохновение, пожалуйста, не скупитесь на лайки и звезды. Вы, безусловно, самая большая движущая сила для меня, чтобы двигаться вперед .GitHub.com/Иветт Л.А. Ю/Б…

Подпишитесь на официальный аккаунт и присоединитесь к группе технического обмена