Цепочка обещаний - аутентификация пользователей с помощью bcrypt mongoose и jwt [duplicate]

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

select
cemetery.cemetery_id as "Cemetery_ID",
GROUP_CONCAT(distinct(names.name)) as "Cemetery_Name",
cemetery.latitude as Latitude,
cemetery.longitude as Longitude,
c.Contact_Info,
d.Direction_Type,
d.Directions

    from cemetery
    left join cemetery_names on cemetery.cemetery_id = cemetery_names.cemetery_id 
    left join names on cemetery_names.name_id = names.name_id 
    left join cemetery_contact on cemetery.cemetery_id = cemetery_contact.cemetery_id 

    left join 
    (
        select 
            cemetery_contact.cemetery_id as cID,
            group_concat(contacts.name, char(32), phone.number) as Contact_Info

                from cemetery_contact
                left join contacts on cemetery_contact.contact_id = contacts.contact_id 
                left join phone on cemetery_contact.contact_id = phone.contact_id 

            group by cID
    )
    as c on c.cID = cemetery.cemetery_id


    left join
    (
        select 
            cemetery_id as dID, 
            group_concat(direction_type.direction_type) as Direction_Type,
            group_concat(directions.value , char(13), char(9)) as Directions

                from directions
                left join direction_type on directions.type = direction_type.direction_type_id

            group by dID


    )
    as d on d.dID  = cemetery.cemetery_id

group by Cemetery_ID

Это кладбище имеет два общих имени, поэтому имена перечислены в разных строках, соединенных одним идентификатором, но с двумя идентификаторами имен, и запрос производит что-то вроде этого & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; CemeteryID & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; Cemetery_Name & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; Appleton, Sulpher Springs & nbsp; & nbsp; 35.4276242832293

524
задан Peter Mortensen 5 June 2016 в 09:49
поделиться

14 ответов

ECMAScript Harmony

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

ECMAScript 8

Вам не нужно ни одного вызова then или callback-функции, как и в асинхронной функции (которая возвращает обещание при вызове), вы можете просто ждать, пока обещания будут разрешены напрямую. Он также имеет произвольные структуры управления, такие как условия, циклы и пункты try-catch, но для удобства они здесь не нужны:

async function getExample() {
    var resultA = await promiseA(…);
    // some processing
    var resultB = await promiseB(…);
    // more processing
    return // something using both resultA and resultB
}

ECMAScript 6

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

Существуют специальные библиотеки (например, co или task.js ), но и многие библиотеки обещаний имеют вспомогательные функции ( Q , Bluebird , , когда , ...), которые делают это асинхронное пошаговое выполнение для вас, когда вы даете им функцию генератора, которая дает обещания.

var getExample = Promise.coroutine(function* () {
//               ^^^^^^^^^^^^^^^^^ Bluebird syntax
    var resultA = yield promiseA(…);
    // some processing
    var resultB = yield promiseB(…);
    // more processing
    return // something using both resultA and resultB
});

Это действительно работало в версии Node.js, начиная с версии 4.0, также несколько браузеров (или их редакционные выпуски) действительно поддерживали синтаксис генератора относительно рано.

ECMAScript 5

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

И затем, существует также множество других языков компиляции JS , предназначенных для облегчения асинхронного программирования. Обычно они используют синтаксис, подобный await (например, Iced CoffeeScript ), но есть и другие, которые имеют Haskell-подобную do -нотацию (например, LatteJs , monadic , PureScript или LispyScript ).

191
ответ дан Bergi 15 August 2018 в 16:30
поделиться
  • 1
    Во-первых, я не думаю, что следует поощрять синтаксис, исключающий Promise.all (он не будет работать в ES6, когда деструктуризация заменит его, а переключение .spread в then дает людям часто неожиданные результаты. - Я не уверен, почему вам нужно использовать дополнение - добавление вещей в прототип обещания не является приемлемым способом для продолжения обещаний ES6, которые, как предполагается, будут расширены (в настоящее время неподдерживаемый) подклассом. – Benjamin Gruenbaum 31 January 2015 в 19:19
  • 2
    @BenjaminGruenbaum: Что вы подразумеваете под синтаксисом & quot ;? Ни один из методов в этом ответе не будет нарушен с ES6. Для переключения spread на деструктурирование then также не должно быть проблем. Re .prototype.augment: Я знал, что кто-то это заметит, мне просто нравилось изучать возможности - собираюсь отредактировать его. – Bergi 31 January 2015 в 20:17
  • 3
    По синтаксису массива я имею в виду return [x,y]; }).spread(... вместо return Promise.all([x, y]); }).spread(..., который не изменился бы при замене разброса для es6, разрушающего сахар, и также не был бы странным краевым случаем, когда обещания обрабатывали возвращаемые массивы по-разному от всего остального. – Benjamin Gruenbaum 31 January 2015 в 20:19
  • 4
    Являются ли функции внутри массива выполненными по порядку? – scaryguy 16 April 2015 в 05:15
  • 5
    @scaryguy: в массиве нет функций, это обещания. promiseA и promiseB - функции (обещания). – Bergi 16 April 2015 в 08:56
  • 6
    О да, на самом деле я имел в виду обещания :) Возможно, это недостаток моего понимания обещаний, извините, хотя. Поэтому, когда вы используете .all или .join, обещания возвращают значения по порядку, правильно? – scaryguy 16 April 2015 в 20:41
  • 7
    Спасибо за ваши ответы. Сейчас я играю с этими генераторами, и мне кажется, что я летаю с ракеткой. :) – Antoine 21 June 2015 в 20:46
  • 8
    @Bergi вам нужно ожидать, что пример функции async получит Sample () из внешнего кода? – arisalexis 28 August 2015 в 17:51
  • 9
    @arisalexis: Да, getExample по-прежнему является функцией, которая возвращает обещание, работая точно так же, как функции в других ответах, но с более сильным синтаксисом. Вы могли бы await вызывать в другой функции async, или вы могли бы привязать .then() к его результату. – Bergi 28 August 2015 в 21:12
  • 10
    вот демонстрация jsfiddle.net/5t6L8dur – kofifus 12 January 2016 в 23:39
  • 11
    Вероятно, это лучший ответ. Обещания - это «Функциональное реактивное программирование», и это часто используется в решении. Например, BaconJs имеет #combineTemplate, который позволяет комбинировать результаты с объектом, который передается по цепочке – U Avalos 23 January 2016 в 05:36
  • 12
    Мне любопытно, почему вы сразу ответили на свой вопрос, спросив об этом? Здесь есть хорошая дискуссия, но мне любопытно. Возможно, вы нашли свои ответы самостоятельно, спросив? – granmoe 6 March 2016 в 06:46
  • 13
    @granmoe: Я опубликовал целую дискуссию цели в качестве канонической дублированной цели – Bergi 6 March 2016 в 12:17
  • 14
    @CapiEtheriel Ответ был написан, когда ES6 был не так широко распространен, как сегодня. Да, может, пришло время обменяться примерами – Bergi 25 May 2017 в 16:47
  • 15
    @Roland Никогда не говорила, что это было :-) Этот ответ был написан в эпоху ES5, где никаких обещаний не было в стандарте вообще, а spread было очень полезно в этом шаблоне. Для более современных решений см. Принятый ответ. Тем не менее, я уже обновил явный-транзитный ответ , и действительно нет веской причины не обновлять его. – Bergi 30 August 2017 в 08:19

Другой ответ, используя последовательный исполнитель nsynjs :

function getExample(){

  var response1 = returnPromise1().data;

  // promise1 is resolved at this point, '.data' has the result from resolve(result)

  var response2 = returnPromise2().data;

  // promise2 is resolved at this point, '.data' has the result from resolve(result)

  console.log(response, response2);

}

nynjs.run(getExample,{},function(){
    console.log('all done');
})

Обновление: добавлен рабочий пример

function synchronousCode() {
     var urls=[
         "https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js",
         "https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js",
         "https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"
     ];
     for(var i=0; i<urls.length; i++) {
         var len=window.fetch(urls[i]).data.text().data.length;
         //             ^                   ^
         //             |                   +- 2-nd promise result
         //             |                      assigned to 'data'
         //             |
         //             +-- 1-st promise result assigned to 'data'
         //
         console.log('URL #'+i+' : '+urls[i]+", length: "+len);
     }
}

nsynjs.run(synchronousCode,{},function(){
    console.log('all done');
})
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>

2
ответ дан amaksr 15 August 2018 в 16:30
поделиться

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

Пользователь является многообещающей моделью Mongoose.

var globalVar = '';

User.findAsync({}).then(function(users){
  globalVar = users;
}).then(function(){
  console.log(globalVar);
});
5
ответ дан Antoine 15 August 2018 в 16:30
поделиться
  • 1
    Обратите внимание, что этот шаблон уже подробно описан в Mutable contextual state answer (а также почему он уродлив - я тоже не большой поклонник) – Bergi 11 August 2015 в 18:56
  • 2
    В вашем случае шаблон кажется бесполезным. Вам вообще не нужен globalVar, просто User.findAsync({}).then(function(users){ console.log(users); mongoose.connection.close() });? – Bergi 11 August 2015 в 18:56
  • 3
    Я не нуждаюсь в этом лично в своем собственном коде, но пользователю может потребоваться запустить больше async во второй функции, а затем взаимодействовать с первоначальным вызовом Promise. Но, как уже упоминалось, я буду использовать генераторы в этом случае. :) – Antoine 11 August 2015 в 19:00
  • 4
    Вы заметили этот ответ ? – Bergi 21 November 2015 в 12:15
  • 5
    Да, я это сделал, сразу после того, как я разместил свой. Тем не менее, я собираюсь оставить его, потому что он объясняет, как фактически встать и работать с использованием ES7, а не просто сказать, что когда-нибудь ES7 будет доступен. – Antoine 21 November 2015 в 20:02
  • 6
    Правильно, я должен уточнить свой ответ, чтобы сказать, что "экспериментальный" плагины для этих уже здесь. – Bergi 22 November 2015 в 12:46

Mutable contextual state

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

function getExample() {
    var resultA;
    return promiseA(…).then(function(_resultA) {
        resultA = _resultA;
        // some processing
        return promiseB(…);
    }).then(function(resultB) {
        // more processing
        return // something using both resultA and resultB
    });
}

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

Это решение имеет несколько Недостатки:

  • Mutable state является уродливым , а глобальные переменные являются злыми .
  • Этот шаблон не работает через функциональные границы, модуляция функций сложнее, так как их объявления не должны выходить из общей области действия
  • . Область переменных не препятствует доступу к ним до их инициализации. Это особенно вероятно для сложных перспективных конструкций (петли, ветвление, выходы), где могут возникать условия гонки. Передавая состояние явно, декларативный дизайн , который обещает поощрять, заставляет более чистый стиль кодирования, который может предотвратить это.
  • Необходимо правильно выбрать область для этих общих переменных. Он должен быть локальным для выполняемой функции, чтобы предотвратить условия гонки между несколькими параллельными вызовами, как это было бы, если бы, например, состояние хранилось на экземпляре.

Библиотека Bluebird поощряет использование объекта, который передается вместе с использованием метода bind() , чтобы назначить объект контекста цепочке обещаний. Он будет доступен из каждой функции обратного вызова через непригодное для использования this ключевое слово . Хотя свойства объекта более подвержены необнаруженным опечаткам, чем переменные, шаблон довольно умный:

function getExample() {
    return promiseA(…)
    .bind({}) // Bluebird only!
    .then(function(resultA) {
        this.resultA = resultA;
        // some processing
        return promiseB(…);
    }).then(function(resultB) {
        // more processing
        return // something using both this.resultA and resultB
    }).bind(); // don't forget to unbind the object if you don't want the
               // caller to access it
}

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

function getExample() {
    var ctx = {};
    return promiseA(…)
    .then(function(resultA) {
        this.resultA = resultA;
        // some processing
        return promiseB(…);
    }.bind(ctx)).then(function(resultB) {
        // more processing
        return // something using both this.resultA and resultB
    }.bind(ctx));
}
50
ответ дан Community 15 August 2018 в 16:30
поделиться
  • 1
    .bind() не требуется для предотвращения утечки памяти – Esailija 31 January 2015 в 16:02
  • 2
    @Esailija: Но не возвращает ли возвращенное обещание ссылку на объект контекста в противном случае? Хорошо, конечно, сбор мусора будет обрабатывать его позже; это не «утечка», если обещание никогда не будет устранено. – Bergi 31 January 2015 в 16:13
  • 3
    Да, но обещания также содержат ссылку на их значения выполнения и причины ошибок ... но ничто не ссылается на обещание, так что это не имеет значения – Esailija 31 January 2015 в 16:25
  • 4
    Пожалуйста, переломите этот ответ на два, поскольку я почти проголосовал за преамбулу! Я думаю, что «тривиальное (но неэлегантное и довольно ошибочное) решение» является самым чистым и простым решением, поскольку он больше не полагается на закрытие и изменчивое состояние, чем ваш принятый автоответ, но все же проще. Закрытия не являются ни глобальными, ни злыми. Аргументы, данные против этого подхода, не имеют для меня никакого смысла, учитывая предпосылки. Какие проблемы модуляции могут быть даны «замечательная длинная плоская цепочка обещаний»? – jib 2 February 2015 в 20:28
  • 5
    Как я сказал выше, Promises - это «Функциональное реактивное программирование». Это анти-шаблон в FRP – U Avalos 23 January 2016 в 05:37
  • 6
    Это же предложение дается как решение «Продвинутой ошибки № 4» в статье Нолана Лоусона о обещаниях pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html . Это хорошо читать. – Robert 4 March 2016 в 17:56
  • 7
    Это точно функция bind в Monads. Haskell предоставляет синтаксический сахар (do-notation), чтобы он выглядел как синтаксис async / wait. – zeronone 6 August 2016 в 09:51
  • 8
    Приятно читать! Эта картина вполне читаема и очень помогла. Спасибо! – Narita 27 March 2018 в 15:57

Синхронный контроль

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

function getExample() {
    var a = promiseA(…);

    return a.then(function() {
        // some processing
        return promiseB(…);
    }).then(function(resultB) {
        // a is guaranteed to be fulfilled here so we can just retrieve its
        // value synchronously
        var aValue = a.value();
    });
}

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

function getExample() {
    var a = promiseA(…);

    var b = a.then(function() {
        return promiseB(…)
    });

    var c = b.then(function() {
        return promiseC(…);
    });

    var d = c.then(function() {
        return promiseD(…);
    });

    return d.then(function() {
        return a.value() + b.value() + c.value() + d.value();
    });
}
86
ответ дан Esailija 15 August 2018 в 16:30
поделиться
  • 1
    Это мой любимый ответ: читаемая, расширяемая и минимальная зависимость от функций библиотеки или языка – Jason 15 April 2016 в 01:21
  • 2
    @Jason: Uh, минимальная зависимость от функций библиотеки & quot ;? Синхронный осмотр - это функция библиотеки и довольно нестандартная для загрузки. – Bergi 25 June 2016 в 19:23
  • 3
    Я думаю, он имел в виду особенности библиотеки – deathgaze 16 August 2017 в 14:53

Менее суровый поворот на «Mutable contextual state»

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

function getExample(){
    //locally scoped
    const results = {};
    return promiseA(...).then(function(resultA){
        results.a = resultA;
        return promiseB(...);
    }).then(function(resultB){
        results.b = resultB;
        return promiseC(...);
    }).then(function(resultC){
        //Resolve with composite of all promises
        return Promise.resolve(results.a + results.b + resultC);
    }).catch(function(error){
        return Promise.reject(error);
    });
}
  • Глобальные переменные являются плохими, поэтому в этом решении используется локально ограниченная переменная, которая не наносит вреда. Он доступен только внутри функции.
  • Мутируемое состояние уродливое, но это не мутирует состояние уродливо. Уродливое изменчивое состояние традиционно относится к модификации состояния аргументов функции или глобальных переменных, но этот подход просто изменяет состояние переменной локального охвата, которая существует с единственной целью агрегирования результатов обещания ... переменная, которая умрет простой смертью
  • Промежуточные обещания не препятствуют доступу к состоянию объекта результатов, но это не приводит к некоторому страшному сценарию, когда одно из обещаний в цепочке будет изгонять и саботировать ваши результаты. Ответственность за установку значений на каждом шаге обещания ограничивается этой функцией, и общий результат будет либо правильным, либо неправильным ... это не будет какой-то ошибкой, которая возникнет спустя годы в производстве (если вы не намерены ее !) [/ ​​g3]
  • Это не приводит к сценарию условий гонки, который возникает из-за параллельного вызова, потому что для каждого вызова функции getExample создается новый экземпляр переменной результатов.
3
ответ дан Jay 15 August 2018 в 16:30
поделиться
  • 1
    По крайней мере, избегайте Promise конструктора antipattern ! – Bergi 25 March 2017 в 16:00
  • 2
    Спасибо @Bergi, я даже не понял, что это анти-шаблон, пока вы не упомянули об этом! – Jay 27 March 2017 в 16:36
  • 3
    это хороший обходной путь для устранения ошибки, связанной с обещаниями. Я использовал ES5 и не хотел добавлять другую библиотеку для работы с обещанием. – nilakantha singh deo 25 May 2018 в 10:19
function getExample() {
    var retA, retB;
    return promiseA(…).then(function(resultA) {
        retA = resultA;
        // Some processing
        return promiseB(…);
    }).then(function(resultB) {
        // More processing
        //retA is value of promiseA
        return // How do I gain access to resultA here?
    });
}

простой способ: D

1
ответ дан Minh Giang 15 August 2018 в 16:30
поделиться

При использовании bluebird вы можете использовать метод .bind для обмена переменными в цепочке обещаний:

somethingAsync().bind({})
.spread(function (aValue, bValue) {
    this.aValue = aValue;
    this.bValue = bValue;
    return somethingElseAsync(aValue, bValue);
})
.then(function (cValue) {
    return this.aValue + this.bValue + cValue;
});

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

http : //bluebirdjs.com/docs/api/promise.bind.html

1
ответ дан T J 15 August 2018 в 16:30
поделиться

Я думаю, вы можете использовать хэш из RSVP.

Что-то вроде ниже:

    const mainPromise = () => {
        const promise1 = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('first promise is completed');
                resolve({data: '123'});
            }, 2000);
        });

        const promise2 = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('second promise is completed');
                resolve({data: '456'});
            }, 2000);
        });

        return new RSVP.hash({
              prom1: promise1,
              prom2: promise2
          });

    };


   mainPromise()
    .then(data => {
        console.log(data.prom1);
        console.log(data.prom2);
    });
1
ответ дан Vishu 15 August 2018 в 16:30
поделиться

В эти дни я также встречаю такие вопросы, как вы. Наконец, я нашел хорошее решение с запросом, это просто и хорошо читать. Я надеюсь, что это может вам помочь.

Согласно how-to-chain-javascript-promises

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

const firstPromise = () => {
    const promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('first promise is completed');
            resolve({data: '123'});
        }, 2000);
    });
};

const secondPromise = (someStuff) => {
    const promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('second promise is completed');
            resolve({newData: `${someStuff.data} some more data`});
        }, 2000);
    });
};

const thirdPromise = (someStuff) => {
    const promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('third promise is completed');
            resolve({result: someStuff});
        }, 2000);
    });
};

firstPromise()
    .then(seondPromise)
    .then(thirdPromise)
    .then(data => {
        console.log(data);
    });
1
ответ дан yzfdjzwl 15 August 2018 в 16:30
поделиться
  • 1
    Это не отвечает на вопрос о том, как получить доступ к предыдущим результатам в цепочке. – Bergi 25 July 2017 в 09:41
  • 2
    Каждое обещание может получить предыдущее значение, каково ваше значение? – yzfdjzwl 26 July 2017 в 07:47
  • 3
    Взгляните на код в вопросе. Цель состоит не в том, чтобы получить результат обещания, которое .then вызвано, но результат до этого. Например. thirdPromise доступа к результату firstPromise. – Bergi 26 July 2017 в 10:29
  • 4
    Извините, я знаю ваш смысл сейчас, это мой первый ответ на stackoverflow, пожалуйста, простите. – yzfdjzwl 26 July 2017 в 12:59
  • 5
    @yzfdjzwl У вас отличная идея! что может помочь в создании всех результатов. Продолжать. – Manohar Reddy Poreddy 29 November 2017 в 10:46
5
ответ дан Antoine 5 September 2018 в 15:35
поделиться
308
ответ дан Bergi 5 September 2018 в 15:35
поделиться
50
ответ дан Community 5 September 2018 в 15:35
поделиться
5
ответ дан Antoine 28 October 2018 в 23:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: