2016-06-23 2 views
1

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

var Promise = require('bluebird'); 

var timer = function(name) { 
    var start = new Date(); 
    return { 
     stop: function() { 
      var end = new Date(); 
      var time = end.getTime() - start.getTime(); 
      console.log('Function:', name, 'finished in', time, 'ms'); 
     } 
    }; 
}; 

function regular (a, cb) { 
    if (a % 2 === 0) return cb(null, a); 
    return cb(a); 
} 

function promise (a) { 
    return new Promise (function (resolve, reject) { 
     if (a % 2 === 0) resolve(a); 
     else reject(a); 
    }); 
} 


var t = timer('regular'); 
var g = 0; 
for (var i = 1; i < 10001; i++) { 
    regular(i, function(odd, even) { 
     if (odd) g = g + (odd * 2); 
     else g = g + (even * 3); 
    }); 
} 
console.log('g:', g); // g: 125015000 
t.stop(); 

var t2 = timer('promise'); 
var h = 0; 
for (var i = 1; i < 10001; i++) { 
    promise(i).then(function(x) {h = h + (x*3);}).catch(function(x) {h = h + (x*2);}); 
} 
console.log('h:', h); // h: 0 
t2.stop(); 

Что интересно есть обещания не изменяет глобальную переменную 'h', как я могу заставить его возвращать тот же результат, что и переменная 'g'?

UPDATE

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

for (var i = 1; i < 10001; i++) { 
    promise(i).then(function(x) { 
     h = h + (x*3); if (x===10000) console.log('h:', h); 
    }).catch(function(x) {h = h + (x*2);}); // h: 75015000 
} 

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

for (var i = 1; i < 10001; i++) { 
    promise(i).then(function(x) { 
     h = h + (x*3); 
    }).catch(function(x) { 
     h = h + (x*2); 
     if (x===9999) console.log('h:', h); // <- attention here 
    }); // h: 125015000 
} 

Может ли кто-нибудь показать мне лучший код и объяснить код выше? (Код выше показывает детерминированный правильный результат, когда i составляет 9999, а не 10000)

+1

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

+0

Я согласен с @ jfriend00. Но так как вы спрашиваете: ваша переменная 'h' ** обновляется **, но' console.log ('h:', h); 'выполняется (асинхронно), прежде чем все эти обещания будут выполнены. Вы можете увидеть это с помощью 'setTimeout (function() {console.log ('h:', h);}, 2000);' – Viktor

+0

@Viktor Можете ли вы показать нам пример, чтобы получить результат ** сразу после ** вычисление? – nobody

ответ

1

Чтобы решить вашу проблему с помощью обещаний, вы можете обернуть все методы then с помощью reduce и послушать все обещания, это обещает последовательно.

если хотите, вы также можете использовать Promise.all() для выполнения всех обещаний параллельно.

function promise (a) { 
 
    return new Promise (function (resolve, reject) { 
 
     if (a % 2 === 0) resolve(a); 
 
     else reject(a); 
 
    }); 
 
}; 
 

 
var timer = function(name) { 
 
    var start = new Date(); 
 
    return { 
 
     stop: function() { 
 
      var end = new Date(); 
 
      var time = end.getTime() - start.getTime(); 
 
      console.log('Function:', name, 'finished in', time, 'ms'); 
 
     } 
 
    }; 
 
}; 
 

 
console.log('Right result', Array.from({length : 10000}, (el, i)=> (i + 1) % 2 === 0 ? (i+1)*3 : (i+1)*2).reduce((a,b)=> a + b)); 
 

 
var t2 = timer('promise'); 
 
var h = 0; 
 
Promise.all(Array.from({length : 10000}, (el, i)=> promise(i + 1).then(x =>{ h += x*3}).catch(x =>{ h += x*2 }) 
 
)) 
 
.then(()=>{ 
 
    console.log('h:', h); 
 
    t2.stop(); 
 
});

+0

Спасибо за ваш код, вы можете показать мне версию Promise.all()? – nobody

+0

@nobody Использовать Promise.all() вот так, предыдущий подход с уменьшением не работал, потому что последний элемент (Promise) в массиве никогда не вызывается с помощью метода, а вывод плохо. –

+1

Большое спасибо. – nobody

2

Обещает ВСЕГДА называть их .then() или обработчиками асинхронно. Даже если они будут решены немедленно, они позволят текущему потоку завершения JS выполнить и асинхронно вызывают обработчики .then() или .catch() на «следующем тике».

Таким образом, ваш console.log('h:', h); выполнен до тех пор, пока не были вызваны какие-либо из .then() обработчиков из цикла. Если вы разместите оператор console.log() внутри обработчиков .then() и .catch(), вы обнаружите, что они вызываются, но ПОСЛЕ вашего console.log('h:', h);.

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

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

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

+0

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

+0

@nobody. Но без секвенирования у вас нет возможности узнать, когда последний будет выполнен, и, таким образом, не получится получить окончательный результат. В реальной ситуации вы, вероятно, должны будете иметь некоторую координацию между вашими обещаниями, по крайней мере, знать, когда будет сделано последнее. Абстрактные или гипотетические вопросы, подобные этому, не так хорошо работают при переполнении стека из-за этих ситуаций. Гораздо лучше задавать реальный мир с помощью кода реального мира, где мы можем избежать абстрактных дискуссий и обсуждать реальные проблемы/решения. Гораздо проще предложить точный ответ на реальную проблему. – jfriend00

+0

@nobody - Когда вы запускаете кучу обещаний параллельно, вы НИКОГДА не должны делать никаких предположений о том, в каком порядке они будут заполняться. Если они являются реальными асинхронными операциями, они могут завершиться в любом порядке. – jfriend00

Смежные вопросы