簡體   English   中英

承諾不會解決

[英]Promise won't resolve

我是Node的新手,但在解決異步Promise時遇到問題。 我的諾言沒有解決,我不確定自己做錯了什么。 我在理解Promise和回調方面仍然遇到困難,因此任何反饋都將有所幫助。

  var filterFiles = function(){
    return new Promise(function(resolve, reject){
      fs.readdir(rootDir, function(err, files){
        if(err) return console.log(err);

        var task = function(file){
          return new Promise(function(resolve, reject){
            if(! /^\..*/.test(file)){
              fs.stat(rootDir + '/' + file, function(err, stats){
                if(stats.isDirectory()){
                  dirArray.push(file);
                  console.log(dirArray.length);
                  resolve(file);
                }
                if(stats.isFile()){
                  fileArray.push(file);
                  console.log(fileArray.length);
                  resolve(file);
                }
              })
            }

          })
        };

        var actions = files.map(task);

        return Promise.all(actions).then(function(resolve, reject){
          resolve({dirArray: dirArray, fileArray: fileArray});
        });
      })
    })
  }

  filterFiles().then(function(data){
    console.log(data);
    var obj = {
      fileArray: fileArray,
      dirArray: dirArray
    };
    res.send(obj);
  })

它至少看到三個錯誤:

  1. 當您擊中此if語句if(! /^\\..*/.test(file)){並且它不執行if塊時,則永遠不會解決父承諾。

  2. fs.stat()上沒有錯誤處理,因此,如果在該調用中遇到錯誤,則將其忽略,並將嘗試使用錯誤的值。

  3. 您對fs.readdir()調用中的錯誤處理不完整,並且會給您帶來永遠無法兌現的承諾(應拒絕時)。


對於健壯的解決方案,您真的不希望在同一代碼中混合使用Promise和回調。 這會帶來很多錯誤的機會,尤其是在錯誤處理方面(如您所見,您至少有三個錯誤-其中兩個在錯誤處理中)。

如果您要使用Promises,則在最低級別對您正在使用的異步操作進行承諾,並僅使用Promise控制您的異步代碼流。 我知道使相關的fs操作實現承諾的最簡單方法是將Bluebird Promise.promisifyAll()庫及其Promise.promisifyAll() 您不必使用該庫。 您可以改為為正在使用的異步操作手動編寫Promise包裝器。

這是使用Bluebird Promise庫的代碼版本:

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));

function filterFiles() {
    return fs.readdirAsync(rootDir).then(function(files) {
        let fileArray = [];
        let dirArray = [];

        // filter out entries that start with .
        files = files.filter(function(f) {
            return !f.startsWith(".");
        });
        return Promise.map(files, function(f) {
            return fs.statAsync(f).then(function(stats) {
                if (stats.isDirectory()) {
                    dirArray.push(f);
                } else {
                    fileArray.push(f);
                }
            });
        }).then(function() {
            // make the resolved value be an object with two properties containing the arrays
            return {dirArray, fileArray};
        });
    });
}



filterFiles().then(function(data) {
    res.json(data);
}).catch(function(err) {
    // put whatever is appropriate here
    res.status(500).end();
});

通過以下更改對它進行了重寫/重組:

  1. 對所有異步操作使用Promise
  2. 修復所有錯誤處理以拒絕返回的承諾
  3. 篩選出以開頭的文件. 在處理任何文件之前同步(簡化了異步處理)。
  4. 使用Promise.map()並行處理值數組。
  5. filterFiles().then()處理程序中,處理錯誤
  6. 您不能res.send()一個Javascript對象,所以我改用了res.json(data) (盡管我不確定您真正想要發送的是什么)。
  7. 用更有效和更簡單的.startsWith()替換正則表達式比較。

如果您不想使用Bluebird Promise庫,則可以為使用的fs方法創建自己的Promise包裝器,如下所示:

fs.readdirAsync = function(dir) {
    return new Promise(function(resolve, reject) {
        fs.readdir(dir, function(err, data) {
            if (err) {
                reject(err);
            } else {
                resolve(data);
            }
        });
    });
}

fs.statAsync = function(f) {
    return new Promise(function(resolve, reject) {
        fs.stat(f, function(err, data) {
            if (err) {
                reject(err);
            } else {
                resolve(data);
            }
        });
    });
}

function filterFiles() {
    return fs.readdirAsync(rootDir).then(function(files) {
        let fileArray = [];
        let dirArray = [];

        // filter out entries that start with .
        files = files.filter(function(f) {
            return !f.startsWith(".");
        });
        return Promise.all(files.map(function(f) {
            return fs.statAsync(f).then(function(stats) {
                if (stats.isDirectory()) {
                    dirArray.push(f);
                } else {
                    fileArray.push(f);
                }
            });
        })).then(function() {
            // make the resolved value be an object with two properties containing the arrays
            return {dirArray, fileArray};
        });
    });
}


filterFiles().then(function(data) {
    res.json(data);
}).catch(function(err) {
    res.status(500).end();
});

您遇到的主要問題是沒有解決或拒絕最外部的Promise。 您可以通過解決Promise.all而不是返回它來解決此問題。

    resolve(
      Promise.all(actions)
        .then(function(resolvedTasks){
          // ... next potential issue is here
          return {dirArray: dirArray, fileArray: fileArray}
        })
    );

(我知道,看起來很尷尬吧?)

接下來,在Promise.all解決之后,您的返回值有點奇怪。 task函數中,您將項目推送到dirArrayfileArray ,但是未在代碼段中聲明或分配它們。 我將假定它們在此代碼范圍內。 在這種情況下,您只需要返回所需的對象。

另外,為了使您的異步代碼更具可讀性,以下是一些技巧:

  • 盡量不要將回調與Promises混合使用
  • 使用Promise庫來保證限於回調的任何代碼。 示例: bluebird的promisifyAll
  • 盡可能避免嵌套回調/承諾

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM