Pull to refresh
16
0
Dmitry @Riim

User

Send message

Набросал:


<script>

function LimitQueue(limit, timeout) {
    this.limit = limit;
    this.timeout = timeout;

    this.jobs = [];
    this.pending = 0;

    this.results = [];

    this._run = this._run.bind(this);
}

LimitQueue.prototype.push = function(jobs) {
    Array.prototype.push.apply(this.jobs, jobs);
};

LimitQueue.prototype._run = function(results) {
    if (results) {
        this.pending = 0;
        Array.prototype.push.apply(this.results, results);

        setTimeout(this._run, this.timeout);

        if (!this.jobs.length) {
            this.callback(this.results);
        }

        return;
    }

    let promises = [];

    for (;;) {
        if (this.pending == this.limit || !this.jobs.length) {
            Promise.all(promises).then(this._run);
            break;
        }

        promises.push(this.jobs.shift()());
        this.pending++;
    }
};

LimitQueue.prototype.onDone = function(cb) {
    this.callback = cb;
    this._run();
};

// ========

let q = new LimitQueue(3, 1000);

q.push(
    [{ name: 'Max1' }, { name: 'Max2' }, { name: 'Max3' }, { name: 'Max4' }, { name: 'Max5' }].map(
        data => () => {
            console.log(1, data.name);

            return new Promise((resolve, reject) => {
                console.log(2, data.name);

                setTimeout(() => {
                    console.log(3, data.name);
                    resolve(data.name);
                }, Math.ceil(Math.random() * 3000));
            });
        }
    )
);

q.onDone(results => {
    console.log(4, results);
});

</script>

В консоли следующее:


1 "Max1"
2 "Max1"
1 "Max2"
2 "Max2"
1 "Max3"
2 "Max3"
[задержка]
3 "Max3"
[задержка]
3 "Max1"
[задержка]
3 "Max2"
[задержка 1000ms]
1 "Max4"
2 "Max4"
1 "Max5"
2 "Max5"
[задержка]
3 "Max5"
[задержка]
3 "Max4"
4 (5) ["Max1", "Max2", "Max3", "Max4", "Max5"]

Завернуть всё это в красивый интерфейс уже не проблема и как видите нет никаких потоков.


UPD: накосячил конечно немного, но суть я думаю понятна.

Реактивное программирование — парадигма программирования, ориентированная на потоки данных и распространение изменений.

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

Логика в том, что на тех задачах, которые умеют обе функции, приведенная тут функция partial таки быстрее.

так вы согласны, что функции можно сравнивать?


light-curry использует arguments вместо spread operator, а это известный убийца производительности.

вы думаете если переписать без arguments это что-то сильно поменяет? Хорошо, попробуйте! Предлагайте ваш вариант, который создаёт более быстрые каррированные функции. Будет интересно посмотреть.

вы решали не ту же самую задачу, а ее надмножество

То есть если моя функция решает ту же задачу, что и функция в статье, плюс может делать что-то ещё, то сравнивать эти функции на одинаковых задачах, которые они обе умеют решать по вашему нельзя? Где логика?))


именно по этой причине функция partial не попала в ваше сравнение

Попала, в приведённом списке light-curry примерно настолько же примитивно сделан. Да, сам по себе он быстрее создаёт каррированную функцию, но созданная функция в три раза медленнее такой же, созданной моей библиотекой. Почему то мне кажется, что скорость создаваемой каррированной функции намного важнее, чем скорость её создания, так как она может быть вызвана множество раз (обычно так и случается). Вы так не думаете?

То есть вас просто название смутило? Функционал библиотеки является надмножеством функционала приведённого примера и полностью его покрывает, тоже относится к библиотекам в приведённом вами списке. Почему все они используют название curry вместо partial я не знаю, может они все ошиблись, а может это вы что-то не понимаете.
Ну я вроде дал ссылку на результаты бенчмарков, в чём-то медленнее, в чём-то быстрее. В чём другая задача? Это вы мне за то, что я поделился своим решением минус влепили? Спасибо, на хабре я уже ничего другого и не жду.
Универсальная функция для частичного применения других функций

простой, но не самый эффективный вариант реализации, когда-то писал свой вариант с бенчмарками относительно других реализаций: https://github.com/Riim/curry#benchmark .

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

Про циклы говорит:


$('.foobar').addClass('bla')

или


Array.from(document.getElementsByClassName("foobar")).forEach(el => {
    el.classList.add('bla');
});
стрелочные функции были придуманы в 1 очередь для работы с классами, необходимость иметь свой this в данном случае нет

в классах такие функции лучше сразу делать методами для возможности переопределения/доопределения при наследовании.
Например такой код:


class Name {
    method() {
        getContacts(res => {
            this.contacts = res.data.contacts;
        });
    }
}

лучше сразу переписать так:


class Name {
    method() {
        getContacts(this._handleResponse, this);
    }

    _handleResponse() {
        this.contacts = res.data.contacts;
    }
}

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

false, 0 и пустая строка превращаются в пустой объект

На практика в большинстве случаев можно расчитывать, что на месте prop1 или prop2 может быть только объект, null и undefined, а prop3 уже не заменяется.


А уж вызов метода в таком стиле выглядит еще страшнее

я и не говорил, что решение универсальное, в каких-то случаях подходит, в каких-то нет. Скажем a?.b я бы на сегодняшний день записал как a && a.b, а вот конструкцию a.b.c.d?.e однозначно как (a.b.c.d || {}).e, вариант a.b.c.d && a.b.c.d.e при не односимвольных именах будет заметно длиннее.

Реализовал не убирая await, пример:


let user = (await User.find<User>({ name: 'Dmitry' }, ['groups']))!;
(await user.groups)![0].printData();

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

Спасибо. Как я написал в статье, я фронтендер, у меня есть парочка мелких проектов где использую эту библиотеку, но говорить о production ready по ним никак нельзя. Тут мне остаётся лишь надеятся, что кто-то попробует использовать в более крупном проекте и расскажет о том, что всё хорошо или о возникших проблемах. Так что если рискнёте, то обязательно отпишитесь, даже если всё будет хорошо работать.

Функции такие и в PostgreSQL есть, вопрос в том, как это на диск при изменениях пишется. Монга перезаписывает весь документ только если какое-то поле выросло в размерах. Как с этим в MySQL?

А что если оставлять await даже если данные сразу выкачиваются? По идее он почти не мешает, а вот если пытаться от него избавиться, то сразу возникают проблемы с типизацией, так как тип будет зависеть от аргументов в find/findAll. Прийдётся указывать что-то типа Promise<Array<User> | null> | User | null, что, конечно, будет совсем не удобно. То есть данные будут забираться сразу и оборачиваться в уже resolved промис.

Есть такое, причём, насколько я понимаю, единственная причина по которой PostgreSQL нельзя назвать полноценной документоориентированной БД — это полная физическая перезапись JSONB при любых изменениях в нём.

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity