2015-08-15 63 views
21

試圖找出如何找到功能與async.eachSeries完全一樣的東西,我需要按順序(不是並行)運行的異步操作列表,但無法找到在本地ES6中執行操作的方式,任何人都可以請指教,好嗎?ES6承諾 - 類似async.each?

p.s.想到發電機/產量,但沒有經驗,所以我沒有意識到它可以幫助我。

編輯1

每個請求,這裏有一個例子:

假定這段代碼:

let model1 = new MongooseModel({prop1: "a", prop2: "b"}); 
let model2 = new MongooseModel({prop1: "c", prop2: "d"}); 

let arr = [model1 , model2]; 

現在,我想在它的一系列運行,而不是平行的,所以使用「異步」NPM很容易:

async.eachSeries(arr, (model, next)=>{ 
    model.save.then(next).catch(next); 
}, err=>{ 
    if(err) return reject(error); 
    resolve(); 
}) 

我q問題是:在ES6中,我可以在本地進行嗎?沒有NPM的「異步」包?

編輯2

隨着異步/等待它很容易做到:

let model1 = new MongooseModel({prop1: "a", prop2: "b"}); 
let model2 = new MongooseModel({prop1: "c", prop2: "d"});  

let arr = [model1 , model2]; 

for(let model of arr){ 
    await model.save(); 
} 
+0

你的意思是,第二個函數取決於第一個函數的結果? – thefourtheye

+0

不一定要依靠它,但必須在先前完成後運行。 –

+0

你應該舉一個例子,說明樣本輸入和預期輸出,以正確解釋問題。 – thefourtheye

回答

0

您可以通過在then回調返回鏈。例如:

new Promise(function(resolve, reject){ 
    resolve(1) 
}).then(function(v){ 
    console.log(v); 
    return v + 1; 
}).then(function(v){ 
    console.log(v) 
}); 

會打印:

這當然工作時異步解決的承諾:

new Promise(function(resolve, reject){ 
    setTimeout(function(){ 
    resolve(1); 
    }, 1000) 
}).then(function(result){ 
    return new Promise(function(resolve, reject){ 
    setTimeout(function(){ 
     console.log(result); 
     resolve(result + 1); 
    }, 1000) 
    }); 
}).then(function(results){ 
    console.log(results); 
}); 

印刷:

+0

謝謝,但我需要它的動態數據集合,而不是一些靜態的已知數量的迭代。 –

+0

@ShlomiSasson這只是一個例子。所有'then'都會返回一個承諾,你需要傳遞迴調並創建承諾。 –

+0

工具包,所以你說的是創建一個遞歸函數,將更多的回調附加到「then」方法? –

14

讓你想調用數據的陣列上一些異步函數,並希望他們依次調用,而不是並行的說。

async.eachSeries()接口是這樣的:

eachSeries(arr, iterator, [callback]) 

這裏是如何模擬與承諾:

// define helper function that works kind of like async.eachSeries 
function eachSeries(arr, iteratorFn) { 
    return arr.reduce(function(p, item) { 
     return p.then(function() { 
      return iteratorFn(item); 
     }); 
    }, Promise.resolve()); 
} 

這假定iteratorFn需要的項目來處理作爲參數,它返回一個承諾。

下面是一個使用示例(即假設你有一個promisified fs.readFileAsync()),並有一個名爲speak()功能完成後,返回一個承諾:

var files = ["hello.dat", "goodbye.dat", "genericgreeting.dat"]; 
eachSeries(files, function(file) { 
    return fs.readFileAsync(file).then(function(data) { 
     return speak(data); 
    }); 
}); 

這可以讓你的承諾基礎設施所有序列。


它也可以讓你手動序列東西(雖然我不知道爲什麼):

function eachSeries(arr, iteratorFn) { 
    return new Promise(resolve, reject) { 
     var index = 0; 

     function next() { 
      if (index < arr.length) { 
       try { 
        iteratorFn(arr[index++]).then(next, reject); 
       } catch(e) { 
        reject(e); 
       } 
      } else { 
       resolve(); 
      } 
     } 
     // kick off first iteration 
     next(); 
    }); 
} 

或者簡化版本,手動鏈的共同承諾:

function eachSeries(arr, iteratorFn) { 
    var index = 0; 

    function next() { 
     if (index < arr.length) { 
      return iteratorFn(arr[index++]).then(next); 
     } 
    } 
    return Promise.resolve().then(next); 
} 

請注意其中一個手動版本必須圍繞iteratorFn()try/catch以確保它是安全的(將異常轉換爲拒絕)。 .then()會自動保證安全,因此其他方案無需手動捕獲異常,因爲.then()已經爲您抓住了它們。

+1

簡潔而優雅。 –

+0

因爲我認爲它必須使用遞歸部分來獲取數組,直到它結束..在這種情況下,我假設我會繼續使用aync.eachSeries .. –

+0

@ShlomiSasson - 在我的第一個示例中沒有什麼遞歸,所以遞歸部分不是必要。它只是使用'array.reduce()'遍歷數組,並使用promise來鏈接所有的操作。 – jfriend00

37

對於那些誰喜歡簡短的回答:

[func1, func2].reduce((p, f) => p.then(f), Promise.resolve()); 
+1

爲什麼Promise.resolve()在第二個參數? –

+3

第二個參數是縮減的[初始值](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce)。例如。這個特殊的例子相當於'Promise.resolve()。then(func1).then(func2)'。 – jib

+2

你是魔術師。正是我需要的。 –

0

//上傳此爲運行較低版本的NodeJS(天青:/)系統 不是最短的,但最好我可以想到的

例如讓我們說「functionWithPromise」返回一些承諾並期望一些項目。

functionWithPromise(item); 

promisesArray =[]; 

//syncornized 
itemsArray.forEach(function (item){ 
    promisesArray.push(functionWithPromise(item)); 
}); 

Promise.all(promisesArray).then(function (values){ 
//profit 
}); 
0

作爲擴展到answer provided by @jib ...你也可以映射項目異步功能的陣列,像這樣:

[item1, item2] 
    .map(item => async (prev_result) => await something_async(item)) 
    .reduce((p, f) => p.then(f), Promise.resolve()) 
    .then(() => console.log('all done')); 

注意如何prev_result將是以前的評估返回的值something_async,這大致相當於async.eachSeriesasync.waterfall之間的雜種。