2016-12-13 25 views
-1

我明白使用Q庫可以很容易地等待一些承諾來完成,然後用對應於那些承諾的結果值列表工作:節點承諾:先用/任何結果(Q庫)

Q.all([ 
    promise1, 
    promise2, 
    . 
    . 
    . 
    promiseN, 
]).then(results) { 
    // results is a list of all the values from 1 to n 
}); 

但是,如果我只對單一,最快的完成結果感興趣,會發生什麼?給出一個用例:假設我有興趣檢查一大堆文件,並且只要找到包含「津巴布韋」一詞的任何文件,我就會滿意。

我能做到這一點是這樣的:

Q.all(fileNames.map(function(fileName) { 
    return readFilePromise(fileName).then(function(fileContents) { 
     return fileContents.contains('zimbabwe') ? fileContents : null; 
    })); 
})).then(function(results) { 
    var zimbabweFile = results.filter(function(r) { return r !== null; })[0]; 
}); 

但我需要處理完所有的文件,即使我已經找到了「津巴布韋」。如果我有一個包含「津巴布韋」的2kb文件和一個不包含「津巴布韋」的30tb文件(並且假設我在異步讀取文件) - 這是愚蠢的!

我希望能夠做的就是得到一個值的時刻任何承諾滿足:

Q.any(fileNames.map(function(fileName) { 
    return readFilePromise(fileName).then(function(fileContents) { 
     if (fileContents.contains('zimbabwe')) return fileContents; 
     /* 
     Indicate failure 
     -Return "null" or "undefined"? 
     -Throw error? 
     */ 
    })); 
})).then(function(result) { 
    // Only one result! 
    var zimbabweFile = result; 
}).fail(function() { /* no "zimbabwe" found */ }); 

用這種方法我會,如果「津巴布韋」中發現無法在我的30TB文件等待我的2kb文件在早期。

但是沒有Q.any這樣的東西!

我的問題:我如何得到這種行爲?

重要注意事項:即使內部承諾之一發生錯誤,也應該無錯地返回。

注:我知道我可以通過在找到第一個有效值時拋出一個錯誤來破解Q.all,但我更願意避免這種情況。

注意:我知道類似Q.any的行爲可能不正確,或者在許多情況下不合適。請相信我有一個有效的用例!

+0

dunno如果Q支持它,但本機的承諾當然會。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race –

+0

@KevinB好點,修正!我可以想象將Q和本地承諾混合並不合適?你知道這個共識是什麼嗎? –

+0

@KevinB在其他消息中,實際上有'Q.race'這樣的東西 - 它沒有記錄,但它存在。如果你添加一個答案,我會給你支票! –

回答

1

您正在混合兩個不同的問題:賽車和取消。

賽車很簡單,您可以使用Promise.race或您最喜愛的承諾庫中的等價物。如果你願意,你可以自己寫成兩行:

function race(promises) { 
    return new Promise((resolve, reject) => 
    promises.forEach(promise => promise.then(resolve, reject))); 
} 

如果有任何承諾被拒絕,這將拒絕。相反,如果你想跳過廢品,只有當所有的承諾拒絕拒絕,然後

function race(promises) { 
    let rejected = 0; 
    return new Promise((resolve, reject) => 
    promises.forEach(promise => promise.then(resolve, 
    () => { if (++rejected === promises.length) reject(); } 
    ); 
} 

或者,你可以用Promise.all,我不會進入這裏使用promise inversion trick

你真正的問題是不同的 - 你顯然想在其他解決方案時「取消」其他承諾。爲此,您將需要額外的專用機器。表示每個處理段的對象將需要一些方法來要求它終止。下面是一些僞代碼:

class Processor { 
    promise() { ... } 
    terminate() { ... } 
} 

現在你可以寫你的種族的版本

function race(processors) { 
    let rejected = 0; 
    return new Promise((resolve, reject) => 
    processors.forEach(processor => processor.promise().then(
    () => { 
     resolve(); 
     processors.forEach(processor => processor.terminate()); 
     }, 
    () => { if (++rejected === processors.length) reject(); } 
    ); 
); 
} 

有各種提案辦理承諾取消時,他們在短短几年內實現這可能使這更容易。