Это не точный ответ, который вы ищете, но это решение, которое мне нужно для моего проекта, и надеюсь, что это поможет кому-то. Это будет перечислять от 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
Конечно, эта проблема была признана и разработчиками языка. Они проделали большую работу, и предложение функций асинхронных функций , наконец, превратилось в
Вам не нужно ни одного вызова 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
}
Пока мы ждали 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, также несколько браузеров (или их редакционные выпуски) действительно поддерживали синтаксис генератора относительно рано.
Однако, если вы хотите / должны быть обратной совместимости вы не можете использовать те, у которых нет транспилятора. Обе функции генератора и асинхронные функции поддерживаются текущей инструментами, см., Например, документацию Babel о генераторах и асинхронных функциях .
И затем, существует также множество других языков компиляции JS , предназначенных для облегчения асинхронного программирования. Обычно они используют синтаксис, подобный await
(например, Iced CoffeeScript ), но есть и другие, которые имеют Haskell-подобную do
-нотацию (например, LatteJs , monadic , PureScript или LispyScript ).
Другой ответ, используя последовательный исполнитель 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>
Я не буду использовать этот шаблон в своем собственном коде, так как я не большой поклонник использования глобальных переменных. Тем не менее, это будет работать.
Пользователь является многообещающей моделью Mongoose.
var globalVar = '';
User.findAsync({}).then(function(users){
globalVar = users;
}).then(function(){
console.log(globalVar);
});
globalVar
, просто User.findAsync({}).then(function(users){ console.log(users); mongoose.connection.close() });
?
– Bergi
11 August 2015 в 18:56
Тривиальное (но неэлегантное и довольно ошибочное) решение состоит в том, чтобы просто использовать переменные более высокого уровня (к которым все обратные вызовы в цепочке имеют доступ) и записывать в них значения результата, когда вы получить их:
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
});
}
Вместо многих переменных можно также использовать (первоначально пустой) объект, на котором результаты сохраняются как динамически созданные свойства.
Это решение имеет несколько Недостатки:
Библиотека 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));
}
bind
в Monads. Haskell предоставляет синтаксический сахар (do-notation), чтобы он выглядел как синтаксис async / wait.
– zeronone
6 August 2016 в 09:51
Присвоение обещаний для более поздних необходимых значений переменным, а затем получение их значения посредством синхронного контроля. В примере используется метод .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();
});
}
Использование объекта с локальным охватом для сбора промежуточных результатов в цепочке обещаний является разумным подходом к заданному вами вопросу. Рассмотрим следующий фрагмент:
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);
});
}
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
При использовании 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;
});
, пожалуйста, проверьте эту ссылку для получения дополнительной информации:
Я думаю, вы можете использовать хэш из 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);
});
Promise.all
, только с объектом вместо массива.
– Bergi
29 August 2017 в 10:35
В эти дни я также встречаю такие вопросы, как вы. Наконец, я нашел хорошее решение с запросом, это просто и хорошо читать. Я надеюсь, что это может вам помочь.
Согласно 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);
});
.then
вызвано, но результат до этого. Например. thirdPromise
доступа к результату firstPromise
.
– Bergi
26 July 2017 в 10:29
Promise.all
(он не будет работать в ES6, когда деструктуризация заменит его, а переключение.spread
вthen
дает людям часто неожиданные результаты. - Я не уверен, почему вам нужно использовать дополнение - добавление вещей в прототип обещания не является приемлемым способом для продолжения обещаний ES6, которые, как предполагается, будут расширены (в настоящее время неподдерживаемый) подклассом. – Benjamin Gruenbaum 31 January 2015 в 19:19spread
на деструктурированиеthen
также не должно быть проблем. Re .prototype.augment: Я знал, что кто-то это заметит, мне просто нравилось изучать возможности - собираюсь отредактировать его.return [x,y]; }).spread(...
вместоreturn Promise.all([x, y]); }).spread(...
, который не изменился бы при замене разброса для es6, разрушающего сахар, и также не был бы странным краевым случаем, когда обещания обрабатывали возвращаемые массивы по-разному от всего остального. – Benjamin Gruenbaum 31 January 2015 в 20:19promiseA
иpromiseB
- функции (обещания). – Bergi 16 April 2015 в 08:56.all
или.join
, обещания возвращают значения по порядку, правильно? – scaryguy 16 April 2015 в 20:41getExample
по-прежнему является функцией, которая возвращает обещание, работая точно так же, как функции в других ответах, но с более сильным синтаксисом. Вы могли быawait
вызывать в другой функцииasync
, или вы могли бы привязать.then()
к его результату. – Bergi 28 August 2015 в 21:12spread
было очень полезно в этом шаблоне. Для более современных решений см. Принятый ответ. Тем не менее, я уже обновил явный-транзитный ответ , и действительно нет веской причины не обновлять его. – Bergi 30 August 2017 в 08:19