2016-04-22 74 views
0

我在下面的函數中遇到了一個小問題。 Promise.map不會等待Folder.create完成並遍歷下一個值。承諾問題

Promise.map(name, function(na){ 
 
    return fs.stat(na.url, function(err, stats){ 
 
    if (typeof stats === 'undefined'){ 
 
     console.log("file doesn't exist"); 
 
     return Folder.create(na).then(function(fd){ 
 
     return mkdirp(root + product.url).then(function(){ 
 
      console.log("Folder Created"); 
 
      return null; 
 
     }); 
 
     }, function(err){ 
 
     console.log(err); 
 
     return reject({message: "Error when creating the folder"}); 
 
     }); 
 
    } 
 
    }); 
 
}).then(function(){ 
 
    console.log('Iteration Done'); 
 
    return resolve({message: "Folder Created!"}); 
 
}); 
 

 
// I GOT : 
 
//file doesn't exist 
 
//file doesn't exist 
 
//file doesn't exist 
 
//Iteration Done 
 
//file doesn't exist 
 
//file doesn't exist 
 
//file doesn't exist 
 
//Iteration Done 
 
//Folder Created 
 
//Folder Created 
 
//Folder Created 
 
//Folder Created 
 
//Folder Created 
 
//Folder Created

+0

可能是因爲'if(typeof stats ==='undefined'){'? – Ioan

+0

不幸的是,它不會改變任何東西 – musecz

回答

0

有幾個問題在這裏:

  1. Promise.map()運行操作的並行每個數組元素,不連續。如果您希望它們連續運行,您可以將{concurrency: 1}作爲選項通過Promise.map()或使用Promise.mapSeries()

  2. fs.stat()所以你的主要回調Promise.map()沒有返回一個承諾等全Promise.map()基礎設施不知道如何等待您的任何結果,不返回的承諾。您可以通過promisify fs.stat()解決該問題。

  3. 您似乎在使用anti-pattern而您的resolve()reject()調用此處。你不會顯示那些來自哪裏的外部定義,但你應該使用從Promise.map()返回的承諾,而不是這樣做。

下面是他們能夠成功地並行運行:

var fs = Promise.promisifyAll(require('fs')); 

Promise.map(name, function(na){ 
    return fs.statAsync(na.url).then(function(err, stats){ 
    if (typeof stats === 'undefined'){ 
     console.log("file doesn't exist"); 
     return Folder.create(na).then(function(fd){ 
     return mkdirp(root + product.url).then(function(){ 
      console.log("Folder Created"); 
      return null; 
     }); 
     }, function(err){ 
     console.log(err); 
     return Promise.reject({message: "Error when creating the folder"}); 
     }); 
    } 
    }); 
}).then(function(){ 
    console.log('Iteration Done'); 
    return ({message: "Folder Created!"}); 
}); 

如果你想與藍鳥連續運行你的業務,你可以通過{concurrency: 1}Promise.map()

Promise.map(name, fn, {concurrency: 1}).then(...); 

或者用途:

Promise.mapSeries(name, fn).then(...) 
+0

在最近的Bluebird中,你應該使用'mapSeries',它也按照預期的順序映射。 – Bergi

+0

@Bergi - 添加了該選項。 – jfriend00

+0

@ jfriend00爲了確保我給出的例子,我使用Promise.reject離開Promise.map循環並回到Promise,它叫做這個。不建議使用這種方式嗎? – musecz

0

fs.stat是一個回調類型的函數,因此,不返回的承諾。你應該修改你的代碼是這樣的

// This might not work directly. I haven't tried to run it 
Promise.map(name, function(na) { 
    return new Promise(function(resolve, reject) { 
     fs.stat(na.url, function(err, stats) { 
      if (typeof stats === 'undefined') { 
       console.log("file doesn't exist"); 
       Folder.create(na).then(function(fd) { 
        return mkdirp(root + product.url); 
       }).then(function() { 
        console.log("Folder Created"); 
        resolve(); 
       }).catch(function(err) { 
        console.log(err); 
        reject({ 
         message: "Error when creating the folder" 
        }); 
       }); 
      } else { 
       resolve(); 
      } 
     }); 
    }); 
}).then(function() { 
    console.log('Iteration Done'); 
    return { 
     message: "Folder Created!" 
    }; 
}); 
+1

而不是永久化OP正在使用的[反模式](https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns),你應該promisify 'fs.stat()'所以你沒有混合普通的回調和承諾。任何時候,在'.then()'處理程序的一個分支中有一個'resolve()',在另一個分支或'.catch()'中有一個'reject()',模式,應該只是回到更高層次的承諾。 – jfriend00