2016-04-22 124 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