RxJS - дает вам плавный опыт программирования (более длинная длина, рекомендуемая коллекция)

JavaScript
RxJS - дает вам плавный опыт программирования (более длинная длина, рекомендуемая коллекция)

предисловие

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

Если вы найдете это полезным после прочтения, я надеюсь поставить лайк автору 😘

концепция

RxJSдаReactive Extensions for JavaScriptсокращение отReactive Extensions, представляет собой наблюдаемый поток данных, основанный наStreamБиблиотека приложений асинхронного программирования, сочетающая шаблон наблюдателя и шаблон итератора.RxJSдаReactive ExtensionsсуществуетJavaScriptреализация выше.

Уведомление! следуетReactНе беда, автор изначально видел это какReact.jsАббревиатура от (позор!!!)

Для незнакомых технологий наша общая идея состоит в том, чтобы открыть Baidu (google), поискать, а затем проверить официальные документы, или найти информацию, которая может понять эту технологию, из разрозненных блогов. Но во многих случаях действительно сложно понять все тонкости технологии всего по нескольким словам.

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

задний план

С точки зрения разработчика, для любой технологии часто говорят о следующих моментах:

  • Сценарий применения?
  • Как приземлиться?
  • Насколько легко начать?
  • Зачем тебе это? Какую проблему он решает?

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

Сценарий применения?

Допустим, у нас есть такое требование:

После того, как мы загрузим большой файл, нам нужно отслеживать его прогресс в режиме реального времени и прекращать мониторинг, когда прогресс достигает 100.

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

Очевидно, что такой способ обработки, несомненно, в определенной степени влечет за собой определенную стоимость разработки и обслуживания для разработчиков, потому что этот процесс больше похож на то, что мы наблюдаем за событием, которое будет запускаться много раз и позволять мне воспринимать его, не только это, но и Чтобы иметь возможность отписаться,PromiseТо, как вы справляетесь с такими вещами, на самом деле недружелюбно, иRxJSУправление асинхронными потоками данных больше соответствует этой парадигме.

Цитирую Вас Да:

лично я склоняюсьRxместо для использованияRx, но не обязательноRx for everything. Подходящим примером является сервер обмена мгновенными сообщениями, такой как множество потоков,Rxвысокоуровневая обработка и, наконец,viewслой очень четкийObservable,ноviewСам слой все еще может использовать существующую парадигму для обработки пользовательских событий.

Как приземлиться?

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

Вот если вы пользовательAngularРазработчики, возможно, вам следует знатьAngularГлубоко интегрированныйRxjs, пока вы используетеAngularFramework, вы неизбежно столкнетесь со знаниями, связанными с RxJ.

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

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

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

Насколько легко начать?

Если вы разработчик с небольшим опытомJavaScriptразработчик, то через несколько минут вы сможетеRxJSПрименяется к какой-то простой практике.

Зачем тебе это? Какую проблему он решает?

Если вы пользовательJavaScriptСталкиваясь с обработкой многочисленных событий и сложным анализом и преобразованием данных, легко ли разработчикам написать очень неэффективный код или раздутые суждения и большое количество грязных логических операторов?

Мало того, вJavaScriptВ мире , с точки зрения многих сценариев, имеющих дело с асинхронными событиями, слово «проблема», кажется, легко упоминается.JSВнимательнее изучите историю обработки асинхронных событий.RxJSпринесенное значение.

异步事件处理方式

Функция обратного вызова Times (обратный вызов)

используемые сцены:

  • обратный вызов события
  • Ajaxпросить
  • Node API
  • setTimeout,setIntervalДождитесь обратного вызова асинхронного события

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

  • forEach
  • map
  • filter
[1, 2, 3].forEach(function (item, index) {
    console.log(item, index);
})

То, как они используются, требует от нас только передачи функции обратного вызова для завершения пакетной обработки набора данных, что очень удобно и понятно.

Но в борьбе с сложным бизнесом мы все еще поддерживаем, если не отказаться от того, как не отказывайтесь от идеи использования цепной функции обратного вызова в следующих обстоятельствах:

fs.readFile('a.txt', 'utf-8', function(err, data) {
    fs.readFile('b.txt', 'utf-8', function(err, data1) {
        fs.readFile('c.txt', 'utf-8', function(err, data2) {
            // ......
        })
    })
})

Конечно, как писатель, вы можете чувствовать, что это очень ясно, ах, ничего плохого. Но если точка его более сложной, если не одинаковая функция, позвоните ему, если каждое содержимое обратного вызова внутри оно очень сложно. Краткосрочный срок, чтобы он мог написать ясно, почему, для каких целей, но через месяц, три месяца, один год спустя, многие дела вы уверены, что вы можете получить оригинальный код оригинала это?

Вам не терпится найти запись о представлении? Какой идиот написал это?shit..., что за бред я написал.

В это время, столкнувшись с бедствием многих разработчиков回调地域, наконец-то кто-то вышел на пользу человечеству...

Эпоха обещаний

PromiseИзначально было предложено сообществом (в конце концов, поскольку мы имеем дело со странными бизнес-кодами каждый день, мы не можем все время выдержать его с обратными вызовами), а затем официальный официальный сайтES6Он добавлен к языковому стандарту и стандартизирован, так что мы можем изначальноnewОдинPromise.

С точки зрения преимуществ,PromiseОн предлагает метод кодирования, отличный от функции обратного вызова. Он использует цепные вызовы, отбрасывает данные обратно по одному слою за раз и может выполнять унифицированный захват исключений. Это не похоже на использование функции обратного вызова для прямого взрыва, и это должно быть во многих один за другим в кодеtry catch.

Без лишних слов, посмотрите на код!


function readData(filePath) {
    return new Promise((resolve, reject) => {
        fs.readFile(filePath, 'utf-8', (err, data) => {
            if (err) reject(err);
            resolve(data);
        })
    });
}

readData('a.txt').then(res => {
    return readData('b.txt');
}).then(res => {
    return readData('c.txt');
}).then(res => {
    return readData('d.txt');
}).catch(err => {
    console.log(err);
})

Напротив, такой способ написания будет больше соответствовать нашей обычной логике мышления, в таком порядке он заставляет людей выглядеть очень комфортно и более благоприятен для сопровождения кода.

преимущество:

  • Если состояние изменится, оно больше не изменится, и вы можете получить тот же результат в любое время.
  • Оптимизация обработки асинхронных событий, что делает запись более удобной.

недостаток:

  • Не могу отменить
  • Ошибка не может бытьtry catch(но вы можете использовать.catchСпособ)
  • когда вpendingНевозможно узнать, на какой стадии он находится, когда он находится в состоянии

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

Функция генератора

ES6недавно представленныйGeneratorфункция, которая может бытьyieldКлючевое слово приостанавливает поток выполнения функции, позволяя изменить поток выполнения, тем самым предоставляя решение для асинхронного программирования. Это также обычная функция по форме, но имеет несколько примечательных особенностей:

  • functionМежду ключевым словом и названием функции стоит звездочка "*" (рекомендуется рядом сfunctionключевое слово)
  • Использовать внутри функцииyield· 表达式,定义不同的内部状态 (可以有多个выход`)
  • позвонить напрямуюGeneratorФункция не выполняется и не возвращает результат операции, а возвращает объект обходчика (Iterator Object)
  • Вызов объекта итератораnextметод, траверсGeneratorКаждое состояние внутри функции
function* read(){
    let a= yield '666';
    console.log(a);
    let b = yield 'ass';
    console.log(b);
    return 2
}
let it = read();
console.log(it.next()); // { value:'666',done:false }
console.log(it.next()); // { value:'ass',done:false }
console.log(it.next()); // { value:2,done:true }
console.log(it.next()); // { value: undefined, done: true }

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

async / await

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

Одно скажу, эта штука действительно проста в использовании.Если бы не совместимость, очень хочется использовать этот метод на большой площади.

Давайте посмотрим, как приятно писать код:


async readFileData() {
    const data = await Promise.all([
        '异步事件一',
        '异步事件二',
        '异步事件三'
    ]);
    console.log(data);
}

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

RxJS

Он используется так же, какPromiseВроде как, но мощнее, чемPromiseОн намного мощнее, может не только управлять данными в виде потоков, но и имеет множество встроенных инструментов и методов, которые позволяют нам легко обрабатывать различные операции на уровне данных, делая наш код гладким как шелк.

Преимущество:

  • Значительное уменьшение размера кода
  • Улучшена читаемость кода
  • хорошая обработка асинхронности
  • Управление событиями, механизм планирования
  • очень богатый оператор
  • декларативный стиль программирования
function readData(filePath) {
    return new Observable((observer) => {
        fs.readFile(filePath, 'utf-8', (err, data) => {
            if (err) observer.error(err);
            observer.next(data);
        })
    });
}

Rx.Observable
.forkJoin(readData('a.txt'), readData('b.txt'), readData('c.txt'))
.subscribe(data => console.log(data));

Здесь показано толькоRxJSВерхушка айсберга, которая может выражать энергию, есть много способов справиться с такого рода сценой.RxJSХорошо справляется с асинхронными потоками данных и имеет множество библиотечных функций. дляRxJSон может конвертировать любойDomсобытие илиPromiseПеревести вobservables.

Предварительные знания

официально вступающийRxJSПеред миром нам сначала нужно прояснить и понять несколько понятий:

  • Реактивное программирование (Reactive Programming)
  • поток(Stream)
  • Шаблон наблюдателя
  • шаблон итератора

Реактивное программирование

Реактивное программирование (Reactive Programming), которая представляет собой событийную модель. В приведенном выше режиме асинхронного программирования мы описали два способа получения результата выполнения предыдущей задачи, один из них — тренировка активного вращения, которую мы называемProactiveСпособ. Другой пассивно получает обратную связь, которую мы называемReactive. Проще говоря, вReactiveВ методе обратная связь о результате предыдущей задачи является событием, и приход этого события инициирует выполнение следующей задачи.

Идея реактивного программирования примерно такова: вы можете использовать includeClickа такжеHoverСоздавайте что угодно, включая событияData stream(Также известный как «поток», подробности в последующих главах).StreamНедорогое и обычное, что угодно может бытьStream: переменные, пользовательский ввод, свойства,Cache, структуры данных и т.д. В качестве примера представьте себеTwitter feedЭто какClick eventsТакойData stream, вы можете прослушать его и ответить соответствующим образом.

响应式编程

Объедините реальность, если вы используетеVue, должен быть в состоянии думать об этом в первый раз,VueРазве концепция дизайна адаптивной парадигмы программирования не является также парадигмой адаптивного программирования?В процессе написания кода нам нужно только обращать внимание на изменения данных, и нам не нужно вручную управлять изменениями представления.Такого рода изDomМодификации слоя будут автоматически изменяться и перерисовываться по мере изменения связанных данных.

поток(Stream)

Потоки как концепции должны быть независимыми от языка. документIOпоток,UnixСтандартные системные потоки ввода и вывода, стандартные потоки ошибок (stdin, stdout, stderr), а также упомянутый в началеTCPпоток и некоторыеWebбазовые технологии (такие какNodejs)правильноHTTPАбстракцию потока запросов/ответов можно увидеть в концепции потока.

В основе программирования ответа природа потока — последовательный сбор инвентаря во временном порядке.

流

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

Шаблон наблюдателя

Можно сказать, что среди многих шаблонов проектирования шаблон наблюдателя играет более очевидную роль во многих сценариях.

Шаблон Observer — это поведенческий шаблон проектирования, который позволяет вам определить механизм подписки, который уведомляет несколько других объектов, которые «наблюдают» за объектом, когда происходит событие.

Используйте практический пример, чтобы понять, например, если вы подписаны на услугу SMS-уведомления об изменении баланса банковской карты, то в это время, пока вы переводите деньги или покупаете товары после использования этой банковской карты для потребления, система банка даст вам push текстовое сообщение, чтобы уведомить вас, сколько денег вы тратите, что на самом деле является режимом наблюдателя.

В этом процессе наблюдаемым объектом является баланс банковской карты, а наблюдателем — пользователь.

观察者模式

преимущество:

  • Отношения связи между целью и наблюдателем уменьшаются, и они представляют собой абстрактные отношения связи.
  • Соответствует принципу инверсии зависимостей.
  • Между целью и наблюдателем устанавливается спусковой механизм.
  • Поддержка широковещательной связи

недостаточный:

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

шаблон итератора

итератор (Iterator) режим также называется курсорным (Sursor) шаблон, в объектно-ориентированном программировании шаблон итератора — это шаблон проектирования, самый простой и наиболее распространенный шаблон проектирования. Шаблон итератора может отделить итеративный процесс от бизнес-логики, позволяя пользователям обращаться к каждому элементу в контейнере через определенный интерфейс, не зная базовой реализации.

迭代器模式

const iterable = [1, 2, 3];
const iterator = iterable[Symbol.iterator]();
iterator.next(); // => { value: "1", done: false}
iterator.next(); // => { value: "2", done: false}
iterator.next(); // => { value: "3", done: false}
iterator.next(); // => { value: undefined, done: true}

Как фронтенд-разработчики, наиболее распространенное развертывание, с которым мы сталкиваемся, этоiteratorСуществует множество интерфейсных структур данных:Map,Set,Array, массив классов и т. д. В процессе их использования мы можем использовать один и тот же интерфейс для доступа к каждому элементу, то есть использовать шаблон итератора.

Iteratorэффект:

  • Обеспечить единый и удобный интерфейс доступа к различным структурам данных;
  • Позволяет расположить элементы структуры данных в определенном порядке;
  • для нового синтаксиса обходаfor...ofпетля реализации

Во многих статьях некоторые любят смешивать итераторы и траверсеры для концептуального анализа, на самом деле они выражают один и тот же смысл, или можно сказать (итераторы равны траверсерам).

Observable

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

r2Xwse.png

Возьмите каштан:

Предположим, вы подписаны на блог или учетную запись службы, которая отправляет статьи (например, общедоступную учетную запись WeChat), а затем, пока общедоступная учетная запись обновляет новый контент, общедоступная учетная запись будет отправлять вам новую статью. учетная записьObservable, источник данных, используемый для создания данных.

Поверьте, что прочитав приведенное выше описание, вы должны быть правыObservableЕсли у вас есть определенное представление о том, что это такое, то с этим легко справиться.RxJSкак создатьObservable.

const Rx = require('rxjs/Rx')

const myObservable = Rx.Observable.create(observer => {
  observer.next('foo');
  setTimeout(() => observer.next('bar'), 1000);
});

мы можем позвонитьObservable.createметод созданияObservable, этот метод принимает в качестве параметра функцию, эта функция вызываетсяproducerфункция для генерацииObservableценность . Параметры этой функцииobserver, внутри функции, вызвавobserver.next()для генерации последовательности значенийObservable.

мы должны игнорироватьobserverэто то, что начинается с созданияObservableС точки зрения метода, по сути, это вызовAPIВещи, очень простые, такие простыеObservableОбъект создан.

Observer

Набор функций обратного вызова, которые умеют прослушиватьObservableпредоставленная стоимость.ObserverВ сигнальном потоке есть роль наблюдателя (сторожевого), который отвечает за наблюдение за статусом выполнения задачи и подачу сигналов в поток.

Observer

Здесь мы просто реализуем внутреннюю структуру:

const observer = {
	next: function(value) {
		console.log(value);
	},
	error: function(error) {
		console.log(error)
	},
	complete: function() {
		console.log('complete')
	}
}

существуетRxJSсередина,Observerявляется необязательным. существуетnext,errorа такжеcompleteВ случае, когда логическая часть обработки отсутствует,ObservableВсе еще работающая, логика обработки для включенного определенного типа уведомления автоматически игнорируется.

Например, мы можем определить это так:

const observer = {
	next: function(value) {
		console.log(value);
	},
	error: function(error) {
		console.log(error)
	}
}

До сих пор нормально работает.

Так как же это вяжется с нами в реальном бою:

const myObservable = Rx.Observable.create((observer) => {
    observer.next('111')
    setTimeout(() => {
        observer.next('777')
    }, 3000)
})

myObservable.subscribe((text) => console.log(text));

используйте прямо здесьsubscribeспособ сделатьobserverподписаться одинObservable, мы можем посмотреть на этоsubscribeОпределение функции, чтобы увидеть, как реализовать подписку:

subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): Subscription;

Исходный код используетсяtsНаписанный код представляет собой документ, который очень понятен. Здесь автор объяснит вам это. С точки зрения отсчета, слева направо:next,error,complete, и является необязательным, мы можем сами выборочно передавать соответствующие обратные вызовы, что подтверждает то, что мы сказали выше.next,errorа такжеcompleteЛогическая часть обработки отсутствует и все еще работает нормально, потому что все они являются необязательными.

Подписка и тема

Subscription

SubscriptionозначаетObservableИсполнение можно почистить. Наиболее распространенным методом этого объекта являетсяunsubscribeметод, он не требует никаких параметров и используется только для очисткиSubscriptionзанятые ресурсы. В то же время он также имеетaddметод позволяет нам отменить несколько подписок.

const myObservable = Rx.Observable.create(observer => {
  observer.next('foo');
  setTimeout(() => observer.next('bar'), 1000);
});
const subscription = myObservable.subscribe(x => console.log(x));
// 稍后:
// 这会取消正在进行中的 Observable 执行
// Observable 执行是通过使用观察者调用 subscribe 方法启动的
subscription.unsubscribe();

Тема

Это прокси-объект, который одновременноObservableЕще одинObserver, он может принять обаObservableПередаваемые данные также могут быть отправлены наobserverпередавать данные, тем временем,Subjectк внутреннемуobserversсписок для многоадресной рассылки (multicast)

Subject

SubjectsпроизвольноObservableЕдинственный способ разделить выполнение с несколькими наблюдателями

На этот раз зоркие читатели обнаружат, что здесь возникло новое понятие — мультикаст.

  • Так что же так транслируется?
  • С многоадресной рассылкой есть ли еще одноадресная рассылка?
  • В чем их отличие?

Далее позвольте автору дать вам лучший анализ этих двух концепций.

单播与多播

Одноадресная передача

обычныйObservable Это одноадресная передача, так что же такое одноадресная?

Unicast означает, что каждый обычныйObservablesЭкземпляр может быть подписан только одним наблюдателем, и новый экземпляр будет создан, когда на него подпишутся другие наблюдатели. это обычное делоObservablesПри подписке разными наблюдателями будет несколько экземпляров.Независимо от того, когда наблюдатель начинает подписываться, каждый экземпляр отправляет значение соответствующему наблюдателю с самого начала.

const Rx = require('rxjs/Rx')

const source = Rx.Observable.interval(1000).take(3);

source.subscribe((value) => console.log('A ' + value))

setTimeout(() => {
    source.subscribe((value) => console.log('B ' + value))
}, 1000)

// A 0
// A 1
// B 0
// A 2
// B 1
// B 2

Не паникуйте, увидев незнакомые звонки, подробный анализ будет позже, здесьsourceВы можете понять, что каждая секунда - это отправка целого числа с шагом 0Observableбудет работать и будет отправлено только три раза (takeФактически оператор ограничивает количество принимаемых номеров и не отправляет данные. ).

Отсюда видно, что два разных наблюдателя подписываются на один и тот же источник (source), один для прямой подписки, а другой для подписки с задержкой в ​​одну секунду.

Из распечатанных результатовAПечать растущего числа с нуля каждую секунду иBЗадержка на секунду, затем начните печать с 0, который виден,Aа такжеBВыполнение полностью раздельное, то есть для каждой подписки создается новый экземпляр.

Во многих сценариях мы можем захотетьBЧтобы иметь возможность не принимать данные с самого начала, а принимать данные, отправляемые в данный момент в момент подписки, для этого необходимо использовать возможности многоадресной рассылки.

многоадресная рассылка

Поэтому, если вы реализуете многоадресные возможности, это для достижения функции США только получают данные в реальном времени.

Может быть, небольшой партнер выскочет в это время, непосредственно подписывайтесь на источник в посредник, а затем пересылать данные вAа такжеBРазве это не сработает?


const source = Rx.Observable.interval(1000).take(3);

const subject = {
	observers: [],
	subscribe(target) {
		this.observers.push(target);
	},
	next: function(value) {
		this.observers.forEach((next) => next(value))
	}
}

source.subscribe(subject);

subject.subscribe((value) => console.log('A ' + value))

setTimeout(() => {
	subject.subscribe((value) => console.log('B ' + value))
}, 1000)

// A 0
// A 1
// B 1
// A 2
// B 2

Давайте сначала проанализируем код,Aа такжеBНет никакой разницы между подпиской и одноадресным кодом, единственное, что меняется, это то, что объекты, на которые они подписываются,sourceсталsubjectА потом посмотри на этоsubjectЧто входит, здесь сделаны некоторые упрощения, убраныerror,completeТакая функция обработки сохраняет толькоnext, затем содержитobserversМассив, который содержит всех подписчиков, предоставляетsubscribeИспользуется наблюдателями для подписки на него.

В использовании, пусть этот посредникsubjectПодписатьсяsource, чтобы добиться унифицированного управления и обеспечить характер данных в реальном времени, потому что в основном дляsourceНапример, есть только один подписчик.

Это в основном для удобства понимания и легкой реализации.RxJSсерединаSubject, где посредника можно заменить напрямуюRxJSизSubjectэкземпляр класса, эффект тот же

const source = Rx.Observable.interval(1000).take(3);

const subject = new Rx.Subject();

source.subscribe(subject);

subject.subscribe((value) => console.log('A ' + value))

setTimeout(() => {
	subject.subscribe((value) => console.log('B ' + value))
}, 1000)

Кроме того, давайте сначала посмотрим, соответствует ли распечатанный результат ожидаемомуAРезультат печати не меняется,BЧисло, напечатанное в первый раз, теперь начинается с 1, то есть данных, которые в настоящее время передаются, что удовлетворяет нашу потребность в получении данных в реальном времени.

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

Помимо вышеперечисленного,RxJSтакже обеспечиваетSubjectТри варианта:

  • BehaviorSubject
  • ReplaySubject
  • AsyncSubject

BehaviorSubject

BehaviorSubjectЭто новая подписка, которая дополнительно выдает самое последнее выпущенное значение.Subject.

rdtonI.png]

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

мы знаем обычныеSubjectТекущие данные будут отправлены только при наличии новых данных, а отправленные данные не будут отправлены после отправки, поэтому в это время мы можем ввестиBehaviorSubjectСопровождение конечного состояния выполняется, потому что наблюдатель, который подписывается на объект, может получать самое последнее значение, отправленное объектом во время подписки, что может удовлетворить нашим вышеуказанным требованиям.

Затем объедините код для анализа этогоSubjectСценарии применения:

const subject = new Rx.Subject();

subject.subscribe((value) => console.log('A:' + value))

subject.next(1);
// A:1
subject.next(2);
// A:2

setTimeout(() => {
	subject.subscribe((value) => console.log('B:' + value)); // 1s后订阅,无法收到值
}, 1000)

Первая демонстрация заключается в использовании обычныхSubjectкак подписанный объект, а затем наблюдательAв объекте экземпляраsubjectпередачаnextПодписывается перед отправкой нового значения, а затем наблюдатель подписывается после задержки в одну секунду, поэтомуAПрием данных нормальный, то на этот раз из-заBОн не был подписан, когда данные были отправлены, поэтому он не получил данные.

Тогда давайте посмотрим наBehaviorSubjectДостигнутый эффект:

const subject = new Rx.BehaviorSubject(0); // 需要传入初始值

subject.subscribe((value: number) => console.log('A:' + value))
// A:0
subject.next(1);
// A:1
subject.next(2);
// A:2

setTimeout(() => {
	subject.subscribe((value: number) => console.log('B:' + value))
	// B:2
}, 1000)

Также из распечатанных результатов, так же, как и в обычномSubjectРазница в том, что в то время как подписка, исходный объект отправляет самое последнее измененное значение (или начальное значение, если оно не изменилось). В это время нашBТакже получил последний статус.

создание экземпляра здесьBehaviorSubjectВам нужно передать начальное значение.

ReplaySubject

в пониманииBehaviorSubjectпонять позжеReplaySubjectэто легче,ReplaySubjectВсе значения будут сохранены, а затем воспроизведены для новых подписчиков, и он предоставляет входной параметр для управления количеством воспроизводимых значений (по умолчанию воспроизводить все).

ReplaySubject]

Какой? Все еще не понимаете? Посмотрите на код:

const subject = new Rx.ReplaySubject(2);

subject.next(0);
subject.next(1);
subject.next(2);

subject.subscribe((value: number) => console.log('A:' + value))
// A:1
// A:2

subject.next(3);
// A:3
subject.next(4);
// A:4

setTimeout(() => {
	subject.subscribe((value: number) => console.log('B:' + value))
	// B:3
	// B:4
}, 1000)

// 整体打印顺序:
// A:1
// A:2
// A:3
// A:4
// B:3
// B:4

Давайте сначала посмотрим на параметры, переданные конструктору,BehaviorSubjectа такжеReplaySubjectВам нужно передать параметр, правильноBehaviorSubjectявляется начальным значением дляReplaySubjectДругими словами, сколько раз нужно воспроизвести предыдущее значение, если счетчик повторов не передан, то будут воспроизведены все переданные значения.

По результатам, если не пройти определенное количество повторов, достигаемый эффект почти такой же, как и введенный ранее эффект unicast.

Таким образом, мы можем проанализировать код, чтобы узнать, сколько раз значение, отправленное исходным объектом, может быть получено наблюдателями в момент подписки.

AsyncSubject

AsyncSubjectтолько тогда, когдаObservableПо завершении выполнения (выполнитьcomplete()), он отправит наблюдателю последнее значение выполнения, если оно завершится с исключением,AsyncSubjectне будет публиковать никаких данных, но будетObserverПередайте уведомление об исключении.

AsyncSubject]

AsyncSubjectОбычно он используется меньше, а первые три используются чаще.

const subject = new Rx.AsyncSubject();
subject.next(1);
subject.subscribe(res => {
	console.log('A:' + res);
});
subject.next(2);
subject.subscribe(res => {
	console.log('B:' + res);
});
subject.next(3);
subject.subscribe(res => {
	console.log('C:' + res);
});
subject.complete();
subject.next(4);

// 整体打印结果:
// A:3
// B:3
// C:3

Из результатов печати на самом деле хорошо понятно, то есть для всех наблюдателей исходный объект будет вызываться только после отправки всех данных.completeТолько после метода наблюдателям будут возвращены последние данные.

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

Холодные наблюдаемые против горячих наблюдаемых

Cold and Hot Observables

Cold Observables

Cold Observablesтолько поobserversКогда вы подпишетесь, он начнет генерировать значения. Это одноадресная рассылка. Количество подписок равно количеству экземпляров подписки. Каждая подписка начинает получать значение из первого сгенерированного значения, поэтому значение, полученное каждой подпиской, одинаково.

Если вы хотите обратиться кCold ObservablesДля получения соответствующего кода просто посмотрите на предыдущий пример одноадресной рассылки.

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

Hot Observables

Hot ObservablesПроизводит значение независимо от того, подписано оно или нет. Это многоадресная рассылка, несколько подписок совместно используют один и тот же экземпляр, и значение получено с начала подписки. Значение, полученное каждой подпиской, отличается в зависимости от того, когда они начали подписываться.

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

"обогрев"

Во-первых, вы можете игнорировать незнакомые функции, которые появляются в коде, что будет подробно рассмотрено позже.

const source = Rx.Observable.of(1, 2).publish();
source.connect();
source.subscribe((value) => console.log('A:' + value));
setTimeout(() => {
	source.subscribe((value) => console.log('B:' + value));
}, 1000);

Здесь первое использованиеRxОператорofсоздалObservable, за которым следуетpublishфункция, вызываемая после созданияconnectфункция начала передачи данных.

Результат выполнения конечного кода - данные не выводятся.На самом деле проще понять причину, проанализировав причину.Поскольку нет подписки при включении передачи данных, а этоHot Observables, ему все равно, подписаны вы на него или нет, он будет отправлять данные сразу после включения, так чтоAа такжеBДанные не получены.

Конечно, если поставитьconnectМетод помещается в конец, затем конечный результатAполучено,Bдо сих пор не могу понять, потому чтоAподписался до начала отправки данных, иBЕще одна секунда.

более интуитивная сцена

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

Вот прямое изменение источника выбросов:

const source = Rx.Observable.interval(1000).take(3).publish();
source.subscribe((value: number) => console.log('A:' + value));
setTimeout(() => {
	source.subscribe((value: number) => console.log('B:' + value));
}, 3000);
source.connect();

// A:0
// A:1
// A:2
// B:2

Здесь мы используемintervalСотрудничатьtakeВторой оператор передает инкрементное число, до трех, то результат печати на этот раз даже более понятны,AТри номера принимаются нормально,BПодписка через три секунды, поэтому получена только последняя цифра 2, что и является мультикастом, описанным выше.

Сравните два

  • Cold Observables: будет легче понять, если мы дадим каштан: например, если мы пойдем на станцию ​​B, чтобы посмотреть шоу и обновить новое шоу, независимо от того, когда мы его смотрим, мы можем посмотреть весь эпизод с самого начала, и это не имеет никакого отношения к тому, смотрят это другие люди или нет., не мешайте друг другу.
  • Hot Observables: Это как когда мы идем на станцию ​​Б смотреть прямую трансляцию.После начала прямой трансляции она начинает играть сразу вне зависимости от того есть подписчики или нет.То есть если вы не подписались на нее на момент начало, то через некоторое время посмотришь, да содержание предыдущего прямого эфира я не знаю.

Разбор оператора, который появляется в приведенном выше коде

при созданииHot Observablesкогда мы использовалиpublishа такжеconnectКомбинация функций фактически вызываетpublishРезультат, возвращаемый после того, как оператор являетсяConnectableObservable, а затем предоставляется на этом объектеconnectметоды позволяют нам контролировать, когда данные отправляются.

  • publish: Этот оператор преобразует нормальныйObservable(Cold Observables) вConnectableObservable.

  • ConnectableObservable:ConnectableObservableэто многоадресный ресурсObservable, может использоваться несколькимиobserversобщая подписка, этоHot Observables.ConnectableObservableявляется подписчиком и истинным источникомObservables(в примере вышеinterval, который отправляет значение каждую секунду, которое является источникомObservables) посредник,ConnectableObservableиз источникаObservablesЗначение принимается и затем пересылается подписчику.

  • connect():ConnectableObservableне отправляет активно значения, он имеетconnectметод, позвонивconnectметод, который позволяет делитьсяConnectableObservableотправить значение. когда мы звонимConnectableObservable.prototype.connectМетод, независимо от того, подписан он или нет, отправит значение. Подписчики используют один и тот же экземпляр, и ценность, которую получают подписчики, зависит от того, когда они начали подписываться.

На самом деле, этот метод ручного управления довольно хлопотный, есть ли более удобный метод работы, например, контролировать подписчиков на подписку перед началом отправки данных, а после отмены всех подписчиков прекратить отправку данных? На самом деле есть, посмотрим на счетчик ссылок(refCount):

подсчет ссылок

В основном используется здесьpublishкомбинироватьrefCountДля достижения эффекта «автоматической блокировки».

const source = Rx.Observable.interval(1000).take(3).publish().refCount();
setTimeout(() => {
	source.subscribe(data => { console.log("A:" + data) });
	setTimeout(() => {
		source.subscribe(data => { console.log("B:" + data) });
	}, 1000);
}, 2000);

// A:0
// A:1
// B:1
// A:2
// B:2

Когда мы смотрим на суть через результаты, мы можем легко обнаружить, что только тогда, когдаAНачинайте отправлять данные только после подписки (AПолученные данные начинаются с 0), и когдаBПри подписке можно получить только текущие отправленные данные, но нельзя получить предыдущие данные.

Мало того, этот «автоблок» перестает отправлять данные, когда все подписчики отписываются.

Планировщики

Используется для управления параллелизмом и представляет собой централизованный планировщик, который позволяет нам координировать, когда происходят вычисления, например.setTimeoutилиrequestAnimationFrameили другие.

  • Планировщик — это структура данных. Он знает, как хранить и упорядочивать задачи на основе приоритета или других критериев.
  • Планировщик — это контекст выполнения. Он указывает, когда и где выполнять задачу (например, немедленно или другой механизм функции обратного вызова (такой какsetTimeoutилиprocess.nextTick) или кадры анимации).
  • Планировщик имеет (виртуальные) часы. Функция планировщика передает своеgetterметодnow()Дает понятие «время». Задачи, запланированные в определенном планировщике, будут строго соответствовать времени, представленному этими часами.

Узнав об этом, я считаю, что все были более или менее правы.RxJSУ меня есть определенное понимание.Не знаю, нашли ли вы вопрос.Приведенные выше примеры кода имеют и синхронный, и асинхронный, но автор не показывает контроль их выполнения.Какой у них механизм выполнения?

На самом деле, их внутреннее планирование зависит отSchedulersЧтобы контролировать время передачи данных, многие операторы устанавливают различныеScheduler, поэтому нам не нужно выполнять специальную обработку, они могут нормально работать синхронно или асинхронно.

const source = Rx.Observable.create(function (observer: any) {
    observer.next(1);
    observer.next(2);
    observer.next(3);
    observer.complete();
});

console.log('订阅前');
source.observeOn(Rx.Scheduler.async) // 设为 async
.subscribe({
    next: (value) => { console.log(value); },
    error: (err) => { console.log('Error: ' + err); },
    complete: () => { console.log('complete'); }
});
console.log('订阅后');

// 订阅前
// 订阅后
// 1
// 2
// 3
// complete

Судя по результатам печати, время отправки данных действительно изменилось с синхронного на асинхронное, и если метод планирования не изменен, печать "после подписки" должна выполняться после отправки данных.

После прочтения примера давайте изучим, какие виды планирования может выполнять этот планировщик:

  • queue
  • asap
  • async
  • animationFrame

queue

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

queueПланировщик использования задержки, его поведениеasyncПланировщик тот же.

При использовании без задержки он планирует данную задачу синхронно - как только задача запланирована. Однако при рекурсивном вызове (т.е. внутри запланированной задачи) другая задача будет запланирована с использованием планировщика очереди, вместо немедленного выполнения задача будет помещена в очередь и будет ожидать завершения текущей задачи.

Это означает, что при использованииqueueКогда планировщик выполняет задачу, вы можете быть уверены, что она завершится до того, как начнутся любые другие задачи, запланированные этим планировщиком.

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

Давайте используем официальный пример, чтобы объяснить, как понимается этот метод планирования:

import { queueScheduler } from 'rxjs';
queueScheduler.schedule(() => {
  queueScheduler.schedule(() => console.log('second'));

  console.log('first');
});

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

Сначала мы звонимqueueSchedulerизscheduleМетод начинает выполняться, а затем снова вызывается функция таким же образом (её тоже можно изменить на рекурсию, но может лучше понять это на этом примере), и передаем функцию, выводимsecond.

Затем продолжайте смотреть на следующее утверждение, обычноеconsole.log('first'), а затем посмотрим на результат печати:

// first
// second

Разве это не немного волшебно, если вы не понимаете, почему, вы можете оглянуться назад и посмотреть впередqueueКак обрабатывать рекурсивное выполнение. То есть, если он вызывается рекурсивно, он будет поддерживать внутреннюю очередь, а затем ждать, пока задачи, добавленные в очередь первыми, будут выполнены первыми (т.console.log('first')будет выполняться после выполненияconsole.log('second'),потому чтоconsole.log('second')Эта задача будет добавлена ​​в очередь позже).

asap

Внутренне основанныйPromiseвыполнить(Nodeконечное применениеprocess.nextTick), он будет использовать самый быстрый асинхронный механизм передачи, если не поддерживаетсяPromiseилиprocess.nextTickилиWeb WorkerизMessageChannelтакже может позвонитьsetTimeoutспособ запланировать.

async

а такжеasapСпособ очень похож, но внутреннее применениеsetInterval Планирование, в основном используется для операторов, основанных на времени.

animationFrame

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

Operators

Концепция оператора

Чистые функции в стиле функционального программирования (pure function), используя что-то вродеmap,filter,concat,flatMapПодождите, пока такие операторы будут работать с коллекциями. Из-за его чистого определения функции мы можем знать, что вызов любого оператора не изменит существующийObservableэкземпляр, но вернет новый на основе исходногоObservable.

несмотря на то чтоRxJSОсноваObservable, но наиболее полезными являются его операторы. Операторы — это основные единицы кода, которые позволяют легко составлять сложный асинхронный код в декларативной манере.

Observable图

реализовать оператор

Предположим, мы не используемRxJSПредоставленный оператор фильтра, так что же делать, если вы хотите реализовать его самостоятельно?

function filter(source, callback) {
    return Rx.Observable.create(((observer) => {
        source.subscribe(
            (v) => callback(v) && observer.next(v),
            (err) => observer.error(err),
            (complete) => observer.complete(complete)
        );
    }))
}
const source = Rx.Observable.interval(1000).take(3);
filter(source, (value) => value < 2).subscribe((value) => console.log(value));

// 0
// 1

Это достигается простымfilterОператор, это очень лаконично?На самом деле основной метод, как было сказано выше, основан на входящемObservable, возвращает новыйObservable.

Сначала код создаетObservable, затем используйте нового наблюдателя, чтобы подписаться на входящий источник, и вызовите функцию обратного вызова, чтобы определить, нужно ли продолжать отправлять значение, если оноfalse, а затем пропустите его напрямую.В соответствии с функцией источника и фильтра, которую мы передали, исходный объект в конечном итоге отправит три числа 0, 1 и 2, а результат печати — 0, 1 и 2 отфильтрованы.

Конечно, мы также можем разместить его вRx.Observable.prototypeчтобы мы могли использоватьthisСпособ получения источника:

Rx.Observable.prototype.filter = function (callback) {
    return Rx.Observable.create(((observer) => {
        this.subscribe(
            (v) => callback(v) && observer.next(v),
            (err) => observer.error(err),
            (complete) => observer.complete(complete)
        );
    }))
}
Rx.Observable.interval(1000).take(3).filter((value) => value < 2).subscribe((value) => console.log(value));

// 0
// 1

Разве это не было бы более кратким, как мы использовали нативные массивыfilterТак же.

Если говорить о разнице между этими двумя методами, то ее на самом деле легче понять.prototype, объект, который может быть создан, можно вызвать напрямую, а другой — определить новую функцию, которую можно использовать для экспорта в вызывающую программу (на самом деле, ее также можно напрямую смонтировать вObservableна статическом свойстве).

Увидев это, оценивается, что некоторые читатели догадались, что автор объяснит дальше.

оператор экземпляра - статический оператор

  • Оператор экземпляра: Обычно это оператор, который может быть вызван непосредственно созданным объектом. Обычно мы используем больше операторов экземпляров, таких какfilter,map,concatи т.п. Более удачное использование операторов экземпляровthis, опуская параметр и сохраняя связанный вызов.
  • Статический оператор:ObservableЯвляетсяclassкласс, мы можем напрямую смонтировать оператор в его статическое свойство, преимущество в том, что его можно вызывать без создания экземпляра, недостаток в том, что его больше нельзя использоватьthisСпособ вызова целевого объекта, но вам нужно передать целевой объект.

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

вышесказанноеfilterНапример, измените его и смонтируйте на статическом свойстве:

Rx.Observable.filter = (source, callback) => {
    return Rx.Observable.create(((observer) => {
        source.subscribe(
            (v) => callback(v) && observer.next(v),
            (err) => observer.error(err),
            (complete) => observer.complete(complete)
        );
    }))
}

Операторы создания

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

create

определение:

  • public static create(onSubscription: function(observer: Observer): TeardownLogic): Observable

После крещения предыдущего кода, я считаю, что всем не чужд этот оператор.

create

createБудуonSubscriptionфункцию в фактическуюObservable. всякий раз, когда кто-то подписывается наObservableкогда,onSubscriptionФункция получитObserverЭкземпляр выполняется как единственный параметр.onSubscriptionдолжен вызывать объект наблюдателяnext, errorа такжеcompleteметод.

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

Изображение выше не имеет прямого отношения к демонстрационному коду.

const source = Rx.Observable.create(((observer: any) => {
    observer.next(1);
    observer.next(2);
    setTimeout(() => {
        observer.next(3);
    }, 1000)
}))

// 方式一
source.subscribe(
    {
        next(val) {
            console.log('A:' + val);
        }
    }
);
// 方式二
source.subscribe((val) => console.log('B:' + val));

// A:1
// A:2
// B:1
// B:2
//- 1s后:
// A:3
// B:3

Естественно, о результате печати говорить не приходится.Aа такжеBБудет печатать 1, 2 отдельно и печатать 3 через 1 с.

Здесь мы можем заметить, что наш вызовsubscribeЭти два метода можно использовать, когдаnext,error,completeТри метода (все необязательные), или способ прямой передачи в функцию, параметры соответственно до и послеnext,error,complete.

empty

определение:

  • public static empty(scheduler: Scheduler): Observable

Как следует из названия, этот оператор создает оператор, который не выдает никаких данных и напрямую отправляет уведомление о завершении.

Некоторые читатели могут спросить здесь, какая польза от этой штуки.

На самом деле это не так, когда он сотрудничает с некоторыми операторами, его роль нельзя недооценивать, например,mergeMap, будет объяснено позже, те, кому не терпится, могут сразу перейти кmergeMap.

from

определение:

  • public static from(ish: ObservableInput<T>, scheduler: Scheduler): Observable<T>

из массива, массивоподобного объекта,Promise, объект или класс итератораObservableобъект создаетObservable.

from

Этот метод немного похожjsсерединаArray.fromметод (который может создать новый массив из массивоподобного или итерируемого объекта), но только вRxJSпревращается вObservableдля использования пользователями.

const source = Rx.Observable.from([10, 20, 30]);
source.subscribe(v => console.log(v));

// 10
// 20
// 30

Судя по коду примера, на самом деле это относительно простое использование.Если вы хотите использовать некоторые данные (например, массивы или массивы, подобные массивам) для существующих проектовRxJSуправлять, тоfromОперация будет хорошим выбором.

fromEvent

определение:

  • public static fromEvent(target: EventTargetLike, eventName: string, options: EventListenerOptions, selector: SelectorMethodSignature<T>): Observable<T>

СоздаватьObservable,ДолженObservableИспускает событие указанного типа из данного объекта события. доступно в среде браузераDomсобытие илиNodeв окружающей средеEventEmitterСобытие и т. д.

fromEvent

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

const click = Rx.Observable.fromEvent(document.getElementById('btn'), 'click');
click.subscribe(x => console.log(x));

Сравните наше использованиеaddEventListenerСпособ мониторинга заключается в том, что этот способ письма более беглый.

fromPromise

определение:

  • public static fromPromise(promise: PromiseLike<T>, scheduler: Scheduler): Observable<T>

С точки зрения названия это уже очевидно, т.PromiseПеревести вObservable, так что мы можем писать код без написания.then,.catchцепные вызовы, как это.

еслиPromise resolvesзначение, выводObservableВыдайте это значение, и все готово. еслиPromiseодеялоrejected, выходObservableБудет выдана соответствующая ошибка.

const source = Rx.Observable.fromPromise(fetch('http://localhost:3000'));
source.subscribe(x => console.log(x), e => console.error(e));

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

Таким образом, мы можем легко получить возвращаемое значение запроса.

interval

определение:

  • public static interval(period: number, scheduler: Scheduler): Observable

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

interval

const source = Rx.Observable.interval(1000);
source.subscribe(v => console.log(v));

Значение по умолчанию начинается с 0. Время, установленное здесь, равно 1 с. Он будет продолжать отправлять данные с указанным интервалом. Как правило, мы можем комбинироватьtakeоператора для ограничения объема передаваемых данных.

of

определение:

  • public static of(values: ...T, scheduler: Scheduler): Observable<T>

а такжеfromСпособность не слишком отличается, но при ее использовании вызывается путем передачи параметров один за другим, что чем-то похоже наjsсерединаconcatметод. также вернетObservable, который, в свою очередь, объединяет параметры, которые вы передаете, и синхронно передает данные.

of

const source = Rx.Observable.of(1, 2, 3);
source.subscribe(v => console.log(v));

// 1
// 2
// 3

Выведите 1, 2, 3 последовательно.

repeat

определение:

  • public repeat(count: number): Observable

Дублирующийся источник данныхnВторосортный,nдля параметра числового типа, который вы передаете.

repeat.png

const source = Rx.Observable.of(1, 2, 3).repeat(3);
source.subscribe(v => console.log(v));

Здесь сofОператор, результат печати состоит в том, чтобы распечатать 1, 2, 3, 1, 2, 3, 1, 2, 3 одновременно и преобразовать 1, 2 и 3, которые были первоначально напечатаны только один раз в три раза.

range

определение:

  • public static range(start: number, count: number, scheduler: Scheduler): Observable

СоздаватьObservable, который выдает последовательность чисел в указанном диапазоне.

научилсяPythonУ маленьких друзей дерева возникает ощущение дежавю.

range.png

const source = Rx.Observable.range(1, 4);
source.subscribe(v => console.log(v));

Распечатать результаты: 1, 2, 3, 4.

Это кажется простым?

оператор преобразования

Итак, что такое оператор преобразования?Как мы все знаем, в нашей повседневной деятельности нам всегда приходится иметь дело с разнообразными данными.Во многих случаях мы не используем непосредственно передаваемые данные, а делаем определенное преобразование, придающее им форму это лучше соответствует нашим потребностям.Именно здесь в игру вступает оператор преобразования.

buffer

определение:

  • public buffer(closingNotifier: Observable<any>): Observable<T[]>

собирать прошлые значения в массив и только тогда, когда другиеObservableЭтот массив создается только при выдаче уведомления. Это эквивалентно наличию буфера, сбору данных, ожиданию прихода сигнала и его освобождению.

buffer;

Смена оператора немного похожа на большую плотину: иногда мы выбираем запас воды, и в определенное время лидер приказывает открыть плотину и выпустить воду.

Возьмите каштан:

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

Это когда нам нужноbufferВ дело вступает оператор:

const btn = document.createElement('button');
btn.innerText = '你点我啊!'
document.body.appendChild(btn);
const click = Rx.Observable.fromEvent(btn, 'click');
const interval = Rx.Observable.interval(1000);
const source = interval.buffer(click);
source.subscribe(x => console.log(x));

Здесь мы непосредственно используемintervalПродемонстрировать интерфейс для получения данных, а затем сотрудничатьbufferФункциональная реализация.

Здесь мы будем ждать четырех секунд, а затем щелкните кнопки, распечатайте значения:[0, 1, 2, 3], затем подождите еще 8 секунд и нажмите кнопку:[4, 5, 6, 7, 8, 9, 10, 11].

Из этого явления нетрудно увидеть, что мы реализовали отправку данных с помощью кнопок. В то же время мы можем обнаружить еще одно явление, отправленные данные будут очищаться прямо в буфере, а затем снова будут собираться новые данные.

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

concatMap

определение:

  • public concatMap(project: function(value: T, ?index: number): ObservableInput, resultSelector: function(outerValue: T, innerValue: I, outerIndex: number, innerIndex: number): any): Observable

Этот оператор еще немного интересен, давайте взглянем на описание на официальном сайте:

concatMap

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

Не знаю, чувствуете ли вы, читатели, "легкое" непонимание, но я легко это понимаю, если приведу небольшой пример:

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

Вышеуказанные сценарии включаютconcatMapНесколько основных моментов и моментов, на которые следует обратить внимание:

  1. Исходное значение отправляет данные, затем вы передаете внутреннийObservableОн начнет работать или отправлять данные, а абонент может получать данные, то есть внутреннийObservableЭто эквивалентно тому, чтобы всегда ждать, пока исходный объект отправит данные перед новым циклом работы, и ждать завершения текущего раунда работы, прежде чем переходить к следующему раунду.
  2. Если текущий раунд работы не был завершен и данные, отправленные исходным объектом, получены, они будут сохранены в очереди, а затем, после завершения текущего раунда, будет проверено, есть ли еще в очереди , и если это так, следующий раунд будет запущен немедленно.
  3. Если внутриObservableРабочее время больше, чем время интервала данных, отправляемых исходным объектом, что приводит к тому, что очередь кэша становится все больше и больше, и, наконец, вызывает проблемы с производительностью.

На самом деле распространено мнение, что на фабричной сборочной линии один отвечает за отправку материалов, а другой отвечает за производство продукции.Observable, продукция на этом заводе будет только готовой продукцией, то есть готовой продукцией, поэтому подписчики могут получить ее только после того, как человек, изготовивший продукт, закончит ее.

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

С помощью понимания кода:

const source = Rx.Observable.interval(3000);
const result = source.concatMap(val => Rx.Observable.interval(1000).take(2));
result.subscribe(x => console.log(x));

Сначала проанализируем структуру кода, мы сначала создадим исходный объект, который отправляет данные каждые три секунды, а затем вызовем метод экземпляраconcatMap, и передать возврат методуObservableФункция объекта, и, наконец, пройтиconcatMapпреобразованныйObservableобъект и подписаться на него.

Результат операции: сначала программа работает, на третью секундуsourceотправит первые данные, а затем мы передаем во внутреннююObservable, начните работать, отправьте два увеличенных числа через две секунды, а затем функция подписки распечатает эти два числа шаг за шагом, ожидая одну секунду, что является 6-й секундой работы программы,sourceОтправьте второй номер, на этот раз повторите описанный выше процесс.

map

определение:

  • public map(project: function(value: T, index: number): R, thisArg: any): Observable<R>

Если вы говорите, что используетеjsв массивеmapЕсли есть много методов, вам может не понадобиться читать их здесь, и использование точно такое же.

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

map.png

const source = Rx.Observable.interval(1000).take(3);
const result = source.map(x => x * 2);
result.subscribe(x => console.log(x));

takeФактически оператор ограничивает количество принимаемых номеров и не отправляет данные.

Это используется для демонстрации того, что значение каждого источника данных умножается на 2 и отправляется подписчику, поэтому напечатанные значения: 0, 2, 4.

mapTo

определение:

  • public mapTo(value: any): Observable

Игнорировать данные, отправленные источником данных, и отправлять только указанное значение (параметр).

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

mapTo.png

const source = Rx.Observable.interval(1000).take(3);
const result = source.mapTo(666);
result.subscribe(x => console.log(x));

Как и в этом коде, источник данных отправляет 0, 1, 2, а подписчик фактически получает три 666.

mergeMap

определение:

  • public mergeMap(project: function(value: T, ?index: number): ObservableInput, resultSelector: function(outerValue: T, innerValue: I, outerIndex: number, innerIndex: number): any, concurrent: number): Observable

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

Ты помнишь здесьemptyКак было сказано во введении операторов, автор оставил дыру и не восполнил ее, т.е.mergeMapа такжеemptyКак это работает вместе? Заполните отверстие здесь.

mergeMap.png

const source = Rx.Observable.interval(1000).take(3);
const result = source.mergeMap(x => x % 2 === 0 ? Rx.Observable.of(x) : Rx.Observable.empty());
result.subscribe(x => console.log(x));

Источник ввода — это источник данных, который отправляет три числа 0, 1 и 2. Мы вызываемmergeMapоператора, и передать функцию, функция которой состоит в том, чтобы отправить его подписчику, если текущее значение, отправленное источником ввода, является четным числом, в противном случае он его не отправит.

здесьmergeMapВ основном сделана возможность интеграции, мы можем комбинировать ее сmapВ сравнении можно найтиmapВозвращаемое значение должно быть числовое значение, иmergeMapВозвращаемое значение должно бытьObservable, то есть мы можем вернуть произвольные преобразования или другие возможностиObservable.

pluck

определение:

  • public pluck(properties: ...string): Observable

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

Например, данные, отправленные источником данных, являются объектом, и объект имеетnameсобственность, и подписчик указывает, что знает об этомnameатрибут, то вы можете использовать этот оператор для извлечения значения атрибута для пользователя.

pluck.png

const source = Rx.Observable.of({name: '张三'}, {name: '李四'});
const result = source.pluck('name');
result.subscribe(x => console.log(x));

// 张三
// 李四

Нет сомнения, что этот оператор предназначен для извлечения атрибутов, что эквивалентно использованиюmapоператор для обработки извлеченногоnameвернуться к подписчику.

scan

определение:

  • public scan(accumulator: function(acc: R, value: T, index: number): R, seed: T | R): Observable<R>

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

С точки зрения использования, мы можем обратиться кjsв массивеreduceфункция.

Допустим, у нас сейчас есть требование, мы хотим аккумулировать данные, отправленные источником данных, и вернуть их подписчику, как нам это сделать?

scan.png

const source = Rx.Observable.interval(1000).take(4);
const result = source.scan((acc, cur) => acc + cur, 0);
result.subscribe(x => console.log(x));

С точки зрения кода источник данных отправляет четыре значения: 0, 1, 2, 3, причем значение, получаемое абонентом каждый раз, будет суммой ранее полученного числа и текущего числа, то есть: 0, 1, 3, 6.

Затем посмотрите на использование, мы даемscanПервый аргумент оператора передается функции, которая принимает два значения:acc(результат предыдущего накопления или начальное значение),cur(текущее значение), второй параметр — начальное значение расчета.

switchMap

определение:

  • public switchMap(project: function(value: T, ?index: number): ObservableInput, resultSelector: function(outerValue: T, innerValue: I, outerIndex: number, innerIndex: number): any): Observable

На самом деле, этоswitchоператор иmapкомбинация операторов,switchОператоры рассматриваются в разделе «Объединение операторов».

Основная роль в первую очередь будет принадлежать множествуObservableСлияние и возможность прерывания, то есть слиянияObservable, определенныйObservableСначала начать отправку данных, в это время абонент может нормально получать свои данные, но в это время другойObservableТоже начал отправлять данные, потом первыйObservableОтправка данных прерывается, и отправляются только данные, отправленные опоздавшим.

Говоря простым языком, когда кто-то говорит, вы вдруг начинаете громко говорить, и вас перебивают, в это время все только и слышат вас.

switchMap.png

const btn = document.createElement('button');
btn.innerText = '我要发言!'
document.body.appendChild(btn);
const source = Rx.Observable.fromEvent(btn, 'click');
const result = source.switchMap(x => Rx.Observable.interval(1000).take(3));
result.subscribe(x => console.log(x));

Функция, реализованная кодом, заключается в том, что когда ученик нажимает на кнопку, начинается отправка числа с 0. В это время, если ученик 1 не закончил отправку данных, а ученик 2 нажимает еще раз, данные Ученик 1 больше не будет отправлен. Начните отправлять второго одноклассника.

Предположим, что после одной точки второй студент нажимает кнопку во вторую секунду, и будет напечатан результат: 0, 1, 0, 1, 2. Здесь, начиная со второго 0, это данные, отправленные вторым ученик.

другие операторы преобразования

Портал официального сайта:оператор преобразования

  • bufferCount
  • bufferTime
  • bufferToggle
  • bufferWhen
  • concatMapTo
  • exhaustMap
  • expand
  • groupBy
  • mergeMapTo
  • mergeScan
  • pairwise
  • partition
  • switchMapTo
  • window
  • windowCount
  • windowTime
  • windowToggle
  • windowWhen

оператор фильтра

debounceTime

определение:

  • public debounceTime(dueTime: number, scheduler: Scheduler): Observable

может быть, для определенногоjsНебольшие партнеры с опытом разработки должны знатьdebounceФункция защиты от сотрясений, тогда некоторые друзья спросят в это время, ее не будет сdebounceПримерно так же? Да, его функция такая же, какdebounceФункция защиты от сотрясений аналогична, но все же есть небольшая разница.

Только по истечении определенного периода времени, когда другое значение источника не было передано,Observableвыдает значение в .

То есть предположим, что источник данных отправляет число каждую секунду, и мы используемdebounceTimeоператора и установите время задержки, затем после того, как источник данных отправит новые данные, если источник данных отправит другие новые данные в течение времени задержки, новые данные будут сначала кэшированы и не будут отправлены, подождите После отправки данных и дожидаясь истечения времени задержки, оно будет отправлено абоненту.Мало того, когда время задержки не истекло и в буфере есть значение, и в это время получено новое значение, то буфер be Он отбросит старые данные, поместит их в новые, а затем подождет, пока не наступит время задержки, прежде чем отправлять их.

debounceTime.png

const source = Rx.Observable.interval(1000).take(3);
const result = source.debounceTime(2000);
result.subscribe(x => console.log(x));

С точки зрения кода мы могли бы также догадаться, каков будет окончательный напечатанный результат?

Сначала мы создаем источник данных, который отправляет число каждую секунду и только три раза, затем используемdebounceTimeПосле обработки и установки времени задержки на 2 секунды, в это время мы наблюдаем за напечатанными данными и обнаруживаем, что в первые три секунды после запуска программы печать данных не производится.Через пять секунд печатается 2, а тогда больше нет печати.теперь,почему так?

Ответ заключается в том, что источник данных каждую секунду будет посылать последовательно три числа 0, 1 и 2. Поскольку мы устанавливаем время задержки равным 2 секундам, то есть мы не можем видеть данные, пока данные не будут Поскольку частота отправки отправляющего источника составляет 1 секунду, время задержки составляет 2 секунды, то есть, если отправка не завершена, невозможно заставить отправляющий источник ждать две секунды перед отправкой новых данных. будет печататься, поэтому сколько бы номеров мы не отправляли из источника данных, в итоге подписчик получает только последний номер.

throttleTime

определение:

  • public throttleTime(duration: number, scheduler: Scheduler): Observable<T>

Представлено, как анти-встряска может забыть о дросселировании своего старого партнера?

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

throttleTime.png

const source = Rx.Observable.interval(1000).take(6);
const result = source.throttleTime(2000);
result.subscribe(x => console.log(x));

// 0
// 3

Результат печати показан выше. На самом деле эффект легко объяснить. Источник данных создается в коде для отправки номера, который увеличивается с 0 каждую секунду. Всего отправляется 6 чисел, то есть 0-5 и использоватьthrottleTimeУстановите две секунды, подписчик не будет заблокирован при получении первого значения, но не получит значение в течение двух секунд после получения одного, то есть он может получить только 3 на четвертой секунде.

distinct

определение:

  • public distinct(keySelector: function, flushes: Observable): Observable

Этот оператор также очень прост для понимания, его можно охарактеризовать одним предложением При использовании этого оператора данные, полученные подписчиком, не будут дублироваться, то есть он используется для фильтрации дублирующихся данных.

distinct.png

const source = Rx.Observable.from([1, 2, 3, 2, 4, 3]);
const result = source.distinct();
result.subscribe(x => console.log(x));

Окончательные результаты работы программы: 1, 2, 3, 4, а повторяющиеся числа отфильтровываются напрямую.

filter

определение:

  • public filter(predicate: function(value: T, index: number): boolean, thisArg: any): Observable

Такому базовому нечего вводить, с массивом мы понимаемfilterМетод ничем не отличается, просто используйте место, где он несовместим.

const source = Rx.Observable.from([1, 2, 3, 2, 4, 3]);
const result = source.filter(x => x !== 3);
result.subscribe(x => console.log(x));

В результате программа работает в дополнение к значению, отличному от 3.

first

определение:

  • public first(predicate: function(value: T, index: number, source: Observable<T>): boolean, resultSelector: function(value: T, index: number): R, defaultValue: R): Observable<T | R>

выдается только источникомObservableПервое из выданных значений (или первое значение, удовлетворяющее условию).

Это похоже на вышеизложенное, и вы можете понять это в основном, прочитав введение, поэтому я не буду здесь вдаваться в подробности.

take

определение:

  • public take(count: number): Observable<T>

только источник излученияObservableN значений, первоначально выпущенных(N = count).

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

skip

определение:

  • public skip(count: Number): Observable

вернутьObservable, ДолженObservableПрыгатьObservableВыдаются первые N значений(N = count).

Например, если предположить, что этот источник данных отправляет 6 значений, вы можете использоватьskipоператора, чтобы пропустить первое число.

const source = Rx.Observable.from([1, 2, 3, 2, 4, 3]);
const result = source.skip(2);
result.subscribe(x => console.log(x));

Результат печати: 3, 2, 4, 3, пропуская первые два числа.

Другие операторы фильтра

Официально предоставленных операторов довольно много, поэтому я не буду их здесь представлять по одному, если интересно, можете зайти на официальный сайт и проверить:оператор фильтра.

  • debounce
  • distinctKey
  • distinctUntilChanged
  • distinctUntilKeyChanged
  • elementAt
  • ignoreElements
  • audit
  • auditTime
  • last
  • sample
  • sampleTime
  • single
  • skipLast
  • skipUntil
  • skipWhile
  • takeLast
  • takeUntil
  • takeWhile
  • throttle

Комбинированный оператор

concatAll

определение:

  • public concatAll(): Observable

Как следует из названия, этот оператор немного похож на нашjsМетод среднего массиваconcatДля большегоObservableСинтезируют один, но в нем есть пометка, что он серийный, то есть объединяет дваObservable, подписчик сначала получит первое значение при получении значенияObservable, после чего начинает получать последнийObservableценность .

concatAll.png

const source1 = Rx.Observable.of(1, 2);
const source2 = source1.map(x => Rx.Observable.interval(1000).take(3));
const result = source2.concatAll();
result.subscribe(x => console.log(x));

Согласно приведенному выше текстовому введению, я считаю, что каждый должен в какой-то степени понять этот код.Да, смысл этого кода в том, что наш источник данных отправляет два числа и используетmapОператор возвращает новыйObservable, в это время для того, чтобы абонент получил несколькоObservable, затем используйтеconcatAllОбъедините его, и результаты, полученные конечным подписчиком, будут: 0, 1, 2, 0, 1, 2.

mergeAll

определение:

  • public mergeAll(concurrent: number): Observable

а такжеconcatAllРазницы почти нет, разница только в том, что она параллельная, то есть объединенная кратнаяObservableДанные отправляются в произвольном порядке.

combineLatest

определение:

  • public combineLatest(other: ObservableInput, project: function): Observable

Множественное числоObservablesсоздатьObservable,ДолженObservableзначение по каждому входуObservableрассчитывается по последнему значению .

Этот оператор света не так легко понять из введения, давайте объясним это на примерах.

combineLatest.png

const s1 = Rx.Observable.interval(2000).take(3);
const s2 = Rx.Observable.interval(1000).take(5);
const result = s1.combineLatest(s2, (a, b) => a + b);
result.subscribe(x => console.log(x));

Результаты печати: 0, 1, 2, 3, 4, 5, 6.

Сначала давайте посмотрим на этоcombineLatestиспользуется, это оператор экземпляра, и здесь демонстрируется преобразованиеs1а такжеs2Объединены вместе, и второй параметр должен быть передан в обратном вызове для обработки объединенного значения. Поскольку здесь мы объединяем только два параметра, мы получаем толькоa,bДва параметра, возвращаемое значение функции обратного вызова — это значение, полученное подписчиком.

Из результатов мы ничего не видим, в основном потому, что процесс выглядит следующим образом:

  1. s2отправляет 0, а на этот разs1Если значение не отправлено, обратный вызов, который мы передаем, не будет выполнен, и подписчик не получит значение.
  2. s1отправляет 0, аs2Последнее отправленное значение равно 0, поэтому вызывается функция обратного вызова, передаются эти два параметра, и, наконец, подписчик получает
  3. s2отправляет 1, аs1Последнее отправленное равно 0, поэтому результат равен 1.
  4. s1отправляет 1, аs2Значение последнего передаваемого составляет 1, результат составляет 2.
  5. s2отправляет значение 2, аs1Последнее отправленное значение было 1, поэтому результат равен 3.
  6. s2отправляет значение 3, аs1Последнее отправленное значение было 1, поэтому результат равен 4.
  7. ...повторите вышеуказанные шаги.

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

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

zip

определение:

  • public static zip(observables: *): Observable<R>

поставить несколькоObservableобъединить, чтобы создатьObservable,ДолженObservableЗначение определяется всеми входамиObservablesЗначения рассчитываются последовательно. Если последним аргументом является функция, эта функция используется для вычисления окончательного выданного значения, в противном случае возвращается массив, содержащий все входные значения по порядку.

С точки зрения непрофессионала, расчет выравнивания последовательности будет выполняться между несколькими источниками, что аналогично предыдущему.combineLatestЕсть разница.

Без лишних слов, вот код:

zip.png

const s1 = Rx.Observable.interval(1000).take(3);
const s2 = Rx.Observable.interval(2000).take(5);
const result = s1.zip(s2, (a, b) => a + b);
result.subscribe(x => console.log(x));

Результаты печати: 0, 2, 4.

Как это понять? Прежде всего, давайте запомним предложение. Числа, используемые для расчета между несколькими источниками, выровнены по порядку, то естьs1первое число выровнятьs2Первое число, это вычисление взаимно однозначного соответствия, которое в конечном итоге получает абонент, - это передача нескольких выровненных чисел в вызов, который мы вызываем.zipПоследняя функция обратного вызова, то есть результат, который используется для вычисления значения и, наконец, возврата пользователю, это необязательно.

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

startWidth

определение:

  • public startWith(values: ...T, scheduler: Scheduler): Observable

вернутьObservableСначала выдает элементы, указанные в качестве параметров, а затем выдает источникObservableТовар выдан.

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

const source = Rx.Observable.interval(1000).take(3);
const result = source.startWith(666)
result.subscribe(x => console.log(x));

Результат печати: 666, 0, 1, 2.

Легко ли это понять?

switch

определение:

  • public switch(): Observable<T>

Подписываясь только на последние выпущенные внутренниеObservable, высший порядокObservableПреобразовать в первый порядокObservable.

Для использования этого оператора мы представили его ранееswitchMapЭтот оператор преобразования уже упоминался, что эквивалентноmap+switch=switchMap.

Возьмите каштан:

const btn = document.createElement('button');
btn.innerText = '我要发言!'
document.body.appendChild(btn);
const source = Rx.Observable.fromEvent(btn, 'click');
const source2 = source.map(x => Rx.Observable.interval(1000).take(3));
const result = source2.switch();
result.subscribe(x => console.log(x));

Эффект приведенного выше кода такой же, какswitchMapПоследовательно, когда пользователь нажимает кнопку, он начинает отправлять данные.Если передача данных не завершена, нажмите кнопку еще раз, чтобы начать новый процесс передачи данных и напрямую отказаться от исходного процесса передачи данных.

другие комбинаторы

Портал официального сайта:Комбинированный оператор

  • combineAll
  • concat
  • exhaust
  • forkJoin
  • merge
  • race
  • withLatestFrom
  • zipAll

многоадресный оператор

Портал официального сайта:многоадресный оператор

  • cache
  • multicast
  • publish
  • publishBehavior
  • publishLast
  • publishReplay
  • share

Быть совершенным...

оператор обработки ошибок

Портал официального сайта:оператор обработки ошибок

  • catch
  • retry
  • retryWhen

Быть совершенным...

оператор инструмента

Портал официального сайта:оператор инструмента

  • do
  • delay
  • delayWhen
  • dematerialize
  • finally
  • let
  • materialize
  • observeOn
  • subscribeOn
  • timeInterval
  • timestamp
  • timeout
  • timeoutWith
  • toArray
  • toPromise

Быть совершенным...

Условия и логические операторы

Портал официального сайта:Условия и логические операторы

  • defaultIfEmpty
  • every
  • find
  • findIndex
  • isEmpty

Быть совершенным...

Математические и агрегатные операторы

Портал официального сайта:Математические и агрегатные операторы

  • count
  • max
  • min
  • reduce

Быть совершенным...

Суммировать

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

мы можем поставитьRxJSМетафора как некое событие, которое может быть испущеноlodashБиблиотека инкапсулирует много сложной логики операций, позволяя нам выполнять преобразование данных и операции более элегантным способом во время использования.

Справочная статья

официальная документация

Руководство для начинающих по реактивному программированию - простой для понимания RxJS

История рыбака и Rxjs, на этот раз я научу вас Rxjs, которые должен знать интерфейс

Создание адаптивных приложений с помощью RxJS

Тщательно понять Observable, Observer, Subject в RxJS