Код не выполняется, пока обещание не выполнит свою работу - PullRequest
1 голос
/ 06 октября 2019

Этот вопрос, который у меня есть, может не иметь ничего общего с угловой концепцией. Но я сталкиваюсь с этим в контексте угловых. Я нажимаю кнопку в угловом шаблоне, и она запускает функцию onSubmit.

scanFiles - это долгосрочная функция, которая возвращает обещание. Я ожидаю, что console.log ("test1") будет распечатан непосредственно перед тем, как будет запущена долго работающая функция. Но этого не произойдет. Он распечатывается только после того, как функция длительного запуска завершена. Почему это так?

    onSubmit(){

        this.scanFiles(this.foldersPath).then((filesPath)=>{
                 //after scan finish 

        })
         .catch((err)=>console.log(err))

        console.log("test1")

    }

Дальнейшие обновления 7 октября 2019 г.)

Как видно ниже, моя функция scanFiles возвращает обещание. Следовательно, независимо от того, что выполняет моя работа с обещаниями, теоретически я думал, что «test1» должен быть распечатан до того, как браузер начнет выполнять работу с обещаниями.

scanFiles(foldersPath: any):Promise<string[]> {
        return new Promise(
            (resolveFn, rejectFn)=>{
                try{

                    const scanResult:string[]= foldersPath.reduce(
                        (prevFolderPath:string[], currFolderPath:string)=> {
                            let files:string[] =  this.fileService.getContentInDirectory (currFolderPath, this.filter.bind(this), this.getProcessDirectoryContentFn(), this.subfolderDepthInput)
                            prevFolderPath.push(...files)
                            return prevFolderPath

                        },new Array<string>())
                    console.log(scanResult)
                    resolveFn(scanResult)
                }
                catch(e){
                    console.log(e)
                    rejectFn(e)
                }
            }
        )
``


Обновлено 8 октября 2019 г. Существует readdirSync ()функция внутри geContentInDirectory

getContentInDirectory(dir:string, filterContentFn?:(fullPath:string)=>boolean, processContentFn?:(fullPath:any)=>string, maxSubFolderDepth?:number ): string[]{

        let paths:string[]=[];

        //const dir_NOT_A_DIRECTORY = 
        if(!dir || !fs.lstatSync(dir).isDirectory()) 
            throw new Error("First Parameter must be a directory")

        fs.readdirSync(dir).forEach(entityName=>{
            let fullPath:string = path.join(dir, entityName)
            let isFile = fs.lstatSync(fullPath).isFile()

            if(maxSubFolderDepth==undefined || maxSubFolderDepth >= 0){
                if(isFile){
                    if(filterContentFn) {
                        if(filterContentFn(fullPath)){
                            let content = processContentFn? processContentFn(fullPath): fullPath
                            paths.push(content)
                        }            
                    }
                }
                else {
                    const depth = maxSubFolderDepth==undefined ? undefined: maxSubFolderDepth-1
                    paths.push(...this.getContentInDirectory(fullPath, filterContentFn, processContentFn, depth))
                }
            }
        })
        return paths;

    }
}

Обновлено 8 октября 2019

Я провел эксперимент, переписав свой код следующим образом: результат "test0", "test2", "test1" напечатанв этой последовательности.

Заключение : Когда создается объект обещания, его долго выполняемое задание, определенное внутри объекта обещания, будет запущено и выполнено немедленно. Как только мои файлы ScanFiles завершат свое задание, "test0 "печатается.

Обратный вызов затем регистрируется (регистрируется, но еще не выполнен) в функции then обещания. Тогда test2" печатается. Затем поток вернется в свой цикл обработки событий и обнаружит, что ему по-прежнему необходимо обрабатывать функцию обратного вызова, в результате чего «test1» печатается

let p= this.scanFiles(this.foldersPath)
console.log("test0")
p.then((filesPath)=>{
  console.log("test1")
 })
 .catch((err)=>console.log(err))

 console.log("test2")

Благодаря пользователю Tomalak дляего решение и объяснение, которые приводят к моему выше понимания.

ОТВЕТ на мой вопрос: мой объект Promise содержит синхронные задачи внутри. Неудивительно, что мой «test1» (см. Мой самый верхний код) распечатывается только после выполнения задач в объекте обещания.

Ответы [ 2 ]

1 голос
/ 08 октября 2019

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

function getContentInDirectory(dir, filterContentFn, processContentFn, maxSubFolderDepth) {
    return new Promise((resolve, reject) => {
        let result = [], pending = 0;
        function worker(currPath, depth) {
            pending++;
            fs.lstat(currPath, (err, stat) => {
                pending--;
                if (err) return reject(err);
                if (stat.isDirectory()) {
                    if (depth >= 0) {
                        pending++;
                        fs.readdir(currPath, (err, children) => {
                            pending--;
                            if (err) return reject(err);
                            children.forEach(name => worker(path.join(currPath, name), depth - 1));
                        });
                    }
                } else if (!filterContentFn || filterContentFn(currPath)) {
                    result.push(processContentFn ? processContentFn(currPath) : currPath);
                }
                if (!pending) resolve(result);
            });
        }
        worker(dir, maxSubFolderDepth >= 0 ? maxSubFolderDepth : Infinity);
    });
}

Существуют различные способы реализации этого, в том числе с помощью API-интерфейса fs Promises. , который доступен с версии узла 10, но еще помечен как «экспериментальный». Вышеприведенное не делает никаких предположений и будет работать с любой версией узла.

Теперь вы можете использовать это в scanFiles в духе:

function scanFiles(foldersPath) {
    let pendingPaths = foldersPath.map(currFolderPath => {
        return getContentInDirectory(currFolderPath, filterFunc, processFunc, depth);
    });
    return Promise.all(pendingPaths).then(results => {
        return Array.prototype.concat.apply([], results);  // flatten
    });
}

и, наконец, в вашем обработчике событий:

onSubmit(){
    this.scanFiles(this.foldersPath).then(filesPath => {
        // after scan finish 
        console.log("this prints last");
    })
    .catch(err => console.log(err));
    console.log("this prints first");
}

Здесь следует отметить, что функция, выполняющая реальную работу, должна быть асинхронной с самого начала, если вы хотите, чтобы ваши функции-потребители также были асинхронными. Переключение с «синхронизирующих» версий функций fs узла на обычные асинхронные аналоги является жизненно важным шагом.

Конечно, это изменение означает, что каждый потребитель getContentInDirectory в вашей программе должен быть изменен на асинхронный. код.

0 голосов
/ 06 октября 2019

Вы можете использовать несколько цепочек вместе:

new Promise(function(resolve, reject) {

  setTimeout(() => resolve(1), 1000); // (*)

}).then(function(result) { // (**)

  alert(result); // 1
  return result * 2;

}).then(function(result) { // (***)

  alert(result); // 2
  return result * 2;

}).then(function(result) {

  alert(result); // 4
  return result * 2;

});

Идея состоит в том, что результат передается через цепочку обработчиков .then.

Здесь поток:

Первоначальное обещание разрешается за 1 секунду (), затем вызывается обработчик .then (). Возвращаемое значение передается следующему обработчику .then ()… и т. Д.

ссылка Цепочка обещаний

Или Вы можетесделайте что-нибудь после того, как все исполнится, запишите это наконец:

let isLoading = true;

fetch(myRequest).then(function(response) {
    var contentType = response.headers.get("content-type");
    if(contentType && contentType.includes("application/json")) {
      return response.json();
    }
    throw new TypeError("Oops, we haven't got JSON!");
  })
  .then(function(json) { /* process your JSON further */ })
  .catch(function(error) { console.error(error); /* this line can also throw, e.g. when console = {} */ })
  .finally(function() { isLoading = false; });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...