Обещание вызывается слишком рано в цепочке?

#javascript

#javascript

Вопрос:

Учитывая следующую функцию:

 function makeTimeout(delay=3000) {
    return new Promise(resolve => {
        setTimeout(() => {
             console.log(`I delayed for ${delay} seconds`);
             resolve(`I delayed for ${delay} seconds`)
        }, delay)
    })
}
 

когда я запускаю makeTimeout(5000).then(makeTimeout(6000)).then(makeTimeout(200)); ,
Я возвращаюсь:

 I delayed for 200 seconds
I delayed for 5000 seconds
I delayed for 6000 seconds
 

разве это не должно происходить последовательно, а 200 второе — в конце?

Комментарии:

1. Нет, потому что вы делаете все тайм-ауты в начале, а затем передаете результаты как .then «обратные вызовы».

2. результат makeTimeout(6000) не является функцией (и это ЕДИНСТВЕННОЕ . затем принимает)… он вызывает функцию

Ответ №1:

Вы вызываете последние два makeTimeout s немедленно, в то время как интерпретатор находится в процессе построения цепочки обещаний. Вместо этого передайте обратные .then вызовы, которые возвращают новое обещание:

 makeTimeout(5000)
  .then(() => makeTimeout(6000))
  .then(() => makeTimeout(200));
 

Живой фрагмент:

 function makeTimeout(delay=300) {
    return new Promise(resolve => {
        setTimeout(() => {
             console.log(`I delayed for ${delay} seconds`);
             resolve(`I delayed for ${delay} seconds`)
        }, delay)
    })
}

makeTimeout(500)
  .then(() => makeTimeout(600))
  .then(() => makeTimeout(20)); 

Комментарии:

1. Спасибо! принял ваш ответ и опубликовал ответ, но вопрос о том, что он работает по-другому при перемещении его в многострочный. Если я должен удалить его, пожалуйста, дайте мне знать

2. В большинстве случаев пробелы не имеют значения, они должны работать нормально с пробелами или без них — см. Фрагмент. Я просто сделал его многострочным для удобства чтения

Ответ №2:

.then принимает два аргумента, (onResolved, onRejected) оба должны быть функциями.

makeTimeout(100) вызывается немедленно и возвращает a Promise , а не a Function

Передача чего-то другого не является ошибкой .then , поскольку, во-первых, так .catch работает — в большинстве библиотек promise .catch(onReject) is просто .then(null, onReject) .then просто игнорирует аргументы, которые не являются функциями, не нарушая цепочку

т. е.

 Promise.resolve(1)
.then(null, null)
.then(console.log, console.error)
 

или

 Promise.reject(1)
.then(null, null)
.then(console.log, console.error)
 

Будет работать так, как будто .then(null, null) его просто нет

Для полноты картины вы также можете изменить makeTimeout , чтобы возвращать функцию, поскольку .then игнорирует любой аргумент, который не является функцией

примечание: дополнительные () в makeTimeout(5000)().then

Это так же справедливо, хотя я бы не стал использовать такой шаблон для такого простого кода

 function makeTimeout(delay=3000) {
    return () => new Promise(resolve => {
        setTimeout(() => {
             console.log(`I delayed for ${delay} seconds`);
             resolve(`I delayed for ${delay} seconds`)
        }, delay)
    })
}

makeTimeout(5000)().then(makeTimeout(6000)).then(makeTimeout(200)); 

Ответ №3:

Я попробовал это, и теперь это работает:

 makeTimeout(5000)
  .then(() => makeTimeout(6000))
  .then(() => makeTimeout(200));
 

но разделение на несколько строк выводит их из строя…почему это?

 makeTimeout(5000)
.then(() => {
     makeTimeout(6000)  
})
.then(() => {
     makeTimeout(200)
});
 

Комментарии:

1. потому что во втором коде вы не возвращаете обещание, которое разрешается после задержки — () => statement это НЕ то же самое, что () => { statement; } — это то же самое, что () => { return statement; }

2. о, в однострочном синтаксисе есть неявный возврат … извините