Я собираюсь кое-чему здесь научиться. Я люблю учиться! Заранее благодарю за любую помощь!
Вот 30 строк кода Node.js JavaScript. Это стандартный поиск по таблице. Для простоты моя «таблица» представляет собой последовательность из 16 целых чисел от 0 до 15. Функция compareRow сообщает, имеет ли угаданная строка r номер строки ниже, равен или выше строки, соответствующей транзакции < эм>тэм>; t требуется номер строки r = t. (Конечно, более длинный код сложнее.) Я удалил все, что мог, чтобы не загромождать вас.
Асинхронные проблемы (и некоторые из вас здесь в прошлых вопросах) побудили меня использовать промисы. Мой более длинный код требует bluebird и дает идентичные результаты. Этот код использует обещания JavaScript.
'use strict'
function compareRow(r, t, low, high) {
return new Promise(function(resolve, reject) {
console.log('compareRow r=' + r + ' t=' + t + ' low=' + low +
' high=', high)
return resolve(r - t)
})
}
function findRow(t) {
let lo = 0, hi = 15, mid
return new Promise(function(resolve, reject) {
let mustBreak = false
let count = 0, maxCount = 3
do {
mid = Math.floor((lo + hi) / 2)
compareRow(mid, t, lo, hi)
.then(function(ans, error) {
console.log('findRow got compareRow(' + mid + ')=' + ans)
if (error) { mustBreak = true; return reject(error) }
else if (ans === 0) { mustBreak = true; return resolve(mid) }
else if (ans < 0) lo = mid
else if (ans > 0) hi = mid
})
} while (!mustBreak && ++count < maxCount)
})
}
findRow(2)
.then(function(ans1, err1) {
console.log('for findRow(2): ans=' + ans1 + ' err=' + err1)
})
Самокритика:
- Использование переменной mustBreak неприемлемо. В каждом месте, где я использовал mustBreak=true, я бы предпочел и break, и вернуть разрешение(n) (или что-то еще).
- Я понимаю, что в функциях обратного вызова JavaScript обрабатывает мои обещания, возвращаемые (например, return resolve(1)), как возвраты из функций обратного вызова, а не из функций обещаний в верхней части функции. Следовательно, при каждом таком вызове JavaScript отслеживает две цепочки выполнения: одну для resolve или reject и одну для кода, указанного после обратного вызова. Ик. Второй — непреднамеренная цепочка исполнения.
- JSHint не любит функцию обратного вызова, включающую ans. Он правильно распознает, что функция находится внутри цикла for. Ick, за исключением того, что этот хороший совет в JSHint может не лучшим образом учитывать функции обратного вызова.
Основываясь на сообщениях console.log, которые я с тех пор удалил, выполнение выполняется так, как я хотел, до строки 17 (compareRow(mid, t, lo, hi)). Я ожидал, что console.log покажет мне что-то вроде:
compareRow r=7 t=2 low=0 high= 15
findRow got compareRow(7)=5
compareRow r=3 t=2 low=0 high= 7
findRow got compareRow(3)=1
compareRow r=1 t=2 low=0 high= 3
findRow got compareRow(1)=-1
compareRow r=1 t=2 low=1 high= 3
findRow got compareRow(3)=1
compareRow r=2 t=2 low=1 high= 3
findRow got compareRow(3)=0
for findRow(2): ans=2 err=undefined
Вместо этого я получил:
compareRow r=7 t=2 low=0 high= 15
compareRow r=7 t=2 low=0 high= 15
compareRow r=7 t=2 low=0 high= 15
findRow got compareRow(7)=5
findRow got compareRow(7)=5
findRow got compareRow(7)=5
Кажется
- Выполнение попадает в compareRow (возможно, своевременно), но не попадает вовремя в функцию обратного вызова, которая получает этот ответ, что приводит к бесконечному циклу.
- Или, по крайней мере, этот цикл был бы бесконечным, за исключением счетчика циклов, который ограничивает цикл тремя циклами.
- Учитывая, что цикл останавливается, похоже, что обратный вызов не случайно обрабатывает ответы (findRow получил compareRow(7)=5) и вызывается столько же раз, сколько выполнялся цикл (три раза).
- К тому времени, когда запускается код обратного вызова, код для обработки вывода больше не прослушивается.
Вопросы:
Есть ли способ побудить планировщик JavaScript обрабатывать код так, как я намереваюсь? (Кажется, это совершенно стандартный вариант использования промисов!)
Как я могу написать этот код лучше?
РЕДАКТИРОВАТЬ: изменения формулировок и вопросов; все с тем же эффектом, что и исходный пост. Удалено много строк кода. Исправлена синтаксическая ошибка.
compareRow
действительно асинхронна? В настоящее время ваш код выглядит так, как будто его лучше было бы написать без промисов :-) - person Bergi   schedule 30.11.2015do while
не будут ждать промисов, которые вы создаете внутри своего тела. Вы не можете использовать такие циклы с асинхронным кодом. Вместо этого используйте рекурсивный подход, при котором вы можете вызвать следующий шаг из асинхронного обратного вызова обещания. - person Bergi   schedule 30.11.2015