Обещание разрешается, но не срабатывает

Я создал сценарий, который просматривает кучу папок и обрабатывает их каждую в пакеты веб-пакетов. Это отлично работает, за исключением того, что я не могу понять, почему Promise вокруг цикла не разрешается.

Некоторые вещи, которые я пробовал:

  • Если я помещаю console.log("hello world") непосредственно перед resolve() в } else { ... }, он выводит журнал.
  • Если я вынесу resolve() из } else { ... }, он разрешится, но остальная часть моей задачи gulp не будет продолжена (отдельная, но связанная проблема).

Я был бы признателен за помощь в выяснении этого. Наиболее релевантный фрагмент кода находится ниже, остальная часть - по ссылке ниже.

// process all the script folders
const process_script_folders = () => {
   return new Promise((resolve) => {
       const FOLDER = script_folders.shift();

       // lint all scripts, except for critical
       if (FOLDER !== "critical") {
           const linted = lint_scripts(js_directory, FOLDER + ".js", source_directory + "/" + FOLDER + "/**/*");
           merged_streams.add(linted);
       }

       process_scripts(js_directory, FOLDER + ".js", source_directory + "/" + FOLDER + "/**/*").then((processed) => {
           merged_streams.add(processed);

           if (script_folders.length > 0) {
               process_script_folders();
           } else {
               // @TODO figure out why this isn't resolving
               resolve();
           }
       });
   });
};

return process_script_folders().then(() => {
    // ... do stuff
    console.log("Testing"); // currently never output
});

https://github.com/JacobDB/new-site/blob/dfeeb3260ab1b314e7562ef313c181adf2ef7f9c/gulp-tasks/scripts.js#L86-L89

Вам нужен return resolve();?

leocreatini 13.09.2018 19:18

Ваш рекурсивный вызов process_script_folders() не разрешает обещание, возвращаемое внешним вызовом

Bergi 13.09.2018 19:20

@bergi Думаю, я понимаю, что ты говоришь, но не совсем понимаю, как с этим справиться. Обещания для меня все еще новы; можете ли вы привести пример того, как этого добиться?

JacobTheDev 13.09.2018 19:39

Вы вызываете метод process_script_folders () рекурсивно и разрешаете обещание внутри другого обещания. Метод resolve () не будет вызываться, потому что вы не разрешаете () свое первое обещание, поэтому метод then не будет выполняться для первого, так как ваш метод решения также не будет вызван.

Anupam 13.09.2018 19:40
0
4
84
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я думаю, проблема связана с тем, как вы выполняете рекурсивный вызов.

Попробуй сделать это

if (script_folders.length > 0) {
    process_script_folders().then(resolve);
} else {
    resolve();
}

Это идея, но это Конструктор Promise антипаттерн: - /

Bergi 13.09.2018 19:24

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

Kevin Aud 13.09.2018 19:43

Нет, рекурсивный - это нормально. Но чтобы сделать это правильно, вы должны передать resolve(process_script_folders()), а еще лучше передать только resolve в качестве обратного вызова в process_scripts, а затем сделать все остальное в обратном вызове then, из которого вы можете получить return process_script_folders();.

Bergi 13.09.2018 19:46
Ответ принят как подходящий

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

if (script_folders.length > 0) {
    process_script_folders();
} 
resolve();

Не могли бы вы так попробовать?

Обновлено: @Bergi прав. Я думаю, что если сделать это так, как указано ниже, он должен работать правильно. Сначала тривиальный пример того, что я предлагаю вам сделать:

let i = 0
const example_processing = () => {
    return new Promise((resolve) => {
        i++
        setTimeout(resolve, 1000);
    }).then(() => {
        console.log(i);
        return i < 10 ? example_processing() : "done"
    });
};
example_processing().then(console.log);

Что касается вашего кода, я думаю, это будет выглядеть примерно так:

const process_script_folders = () => {
    return new Promise((resolve) => {
        const FOLDER = script_folders.shift();

        // lint all scripts, except for critical
        if (FOLDER !== "critical") {
            const linted = lint_scripts(js_directory, FOLDER + ".js", source_directory + "/" + FOLDER + "/**/*");
            merged_streams.add(linted);
        }

        process_scripts(js_directory, FOLDER + ".js", source_directory + "/" + FOLDER + "/**/*").then((processed) => {
            merged_streams.add(processed);
            resolve();
        });
    }).then(() => script_folder.length > 0 ? process_script_folders() : "done");
 };

Нет, таким образом, если разрешает до, завершая самые внутренние рекурсивные вызовы

Bergi 13.09.2018 19:25

@Bergi Вы правы. Пожалуйста, проверьте мой измененный ответ.

etarhan 13.09.2018 19:52

Вызов process_script_folders из setTimeout не принесет никакой пользы, но последний фрагмент идеален!

Bergi 13.09.2018 19:53

@Bergi я привел этот пример, чтобы имитировать некоторую обработку. Я понимаю, что наличие одинаковых имен функций немного сбивает с толку, я редактировал это сейчас. Это было просто для иллюстрации. Последний фрагмент кода - это фактически предлагаемое мной решение.

etarhan 13.09.2018 19:54

Ах я вижу. Тем не менее, для этого setTimeout должен находиться строго внутри new Promise :-) Я преобразовал его в исполняемый фрагмент.

Bergi 13.09.2018 20:00

Ах, почти уверен, что я понимаю, что здесь происходит, и мой сценарий теперь работает отлично. Большое спасибо!

JacobTheDev 13.09.2018 20:13

Рад, что смог помочь! с некоторой поправкой от @Bergi;)

etarhan 13.09.2018 20:14

Другие вопросы по теме