2017-10-16 78 views
0

我以前問這裏發現了一個問題: Retaining Data across multiple promise chains節點未處理的承諾問題

我最終使用T.J.克羅德的答案爲我的基本代碼,並做了許多改變。但是我注意到節點中有些奇怪的東西,我似乎無法克服。我回到了他提供的基本代碼,這個問題似乎也在那裏。

這裏是例子:

"use strict"; 

// For tracking our status 
class Status { 
    constructor(total = 0, count = 0) { 
     this.id = ++Status.id; 
     this.total = total; 
     this.count = count; 
    } 
    addCall() { 
     ++this.total; 
     return this; 
    } 
    addProgress() { 
     ++this.count; 
     return this; 
    } 
    toString() { 
     return `[S${this.id}]: Total: ${this.total}, Count: ${this.count}`; 
    } 
} 
Status.id = 0; 

// The promise subclass 
class RepoPromise extends Promise { 
    constructor(executor) { 
     super(executor); 
     this.s = new Status(); 
    } 
    // Utility method to wrap `then`/`catch` callbacks so we hook into when they're called 
    _wrapCallbacks(...callbacks) { 
     return callbacks.filter(c => c).map(c => value => this._handleCallback(c, value)); 
    } 
    // Utility method for when the callback should be called: We track that we've seen 
    // the call then execute the callback 
    _handleCallback(callback, value) { 
     this.s.addProgress(); 
     console.log("Progress: " + this.s); 
     return callback(value); 
    } 
    // Standard `then`, but overridden so we track what's going on, including copying 
    // our status object to the new promise before returning it 
    then(onResolved, onRejected) { 
     this.s.addCall(); 
     console.log("Added: " + this.s); 
     const newPromise = super.then(...this._wrapCallbacks(onResolved, onRejected)); 
     newPromise.s = this.s; 
     return newPromise; 
    } 
    // Standard `catch`, doing the same things as `then` 
    catch(onRejected) { 
     this.s.addCall(); 
     console.log("Added: " + this.s); 
     const newPromise = super.catch(...this._wrapCallbacks(onRejected)); 
     newPromise.s = this.s; 
     return newPromise; 
    } 
} 

// Create a promise we'll resolve after a random timeout 
function delayedGratification() { 
    return new Promise(resolve => { 
     setTimeout(_ => { 
      resolve(); 
     }, Math.random() * 1000); 
    }); 
} 

// Run! Note we follow both kinds of paths: Chain and diverge: 
const rp = RepoPromise.resolve('Test'); 
rp.then(function(scope) { 
    return new Promise((resolve, reject) => { 
     console.log(' Rejected') 
     reject(scope) 
    }) 
}) 
.catch(e => {console.log('Never Makes it')}) 

,當我跑這跟:node test.js我得到以下輸出

Added: [S1]: Total: 1, Count: 0 
Added: [S1]: Total: 2, Count: 0 
Added: [S1]: Total: 3, Count: 0 
Progress: [S1]: Total: 3, Count: 1 
    Rejected 
(node:29364) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Test 
(node:29364) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. 

注意,控制檯日誌"never makes it"不存在,還要注意,我已經解決了catch運行兩次的問題,因爲它是then(null, function(){})的簡單語法糖,因此您可以忽略該問題。

爲什麼catch沒有按照我的預期工作?當我以正常的承諾來做到這一點時,沒有問題,如下所示。所以我知道_wrapCallbacks導致這個問題,我只是不知道爲什麼,或者如何解決這個問題。

const rp = Promise.resolve('Test'); 
rp.then(function(scope) { 
    return new Promise((resolve, reject) => { 
     console.log(' Rejected') 
     reject(scope) 
    }) 
}) 
.catch(e => {console.log('Makes it')}) 

回答

1

catch執行您的承諾不起作用。請注意,原生catch實現爲return this.then(null, callback) - 調用super.catch將直接返回到您的then實現。

而你的then實現有一個嚴重的錯誤:它不喜歡在函數前得到一個參數null。觀察上述通話,當你這樣做會發生什麼:

_wrapCallbacks(...callbacks) { 
    return callbacks.filter(c => c).map(…); 
//     ^^^^^^^^^^^^^^^ 
} 
then(onResolved, onRejected) { 
    … 
    const newPromise = super.then(...this._wrapCallbacks(onResolved, onRejected)); 
    … 
} 

這會簡單地刪除從參數數組的null並通過onrejected回調爲onfulfilled代替。您將要刪除的filter,並使用三元的映射函數:

_wrapCallbacks(...callbacks) { 
    return callbacks.map(c => typeof c == "function" 
     ? value => this._handleCallback(c, value) 
     : c); 
} 

您也可以只下降了覆蓋catch

+0

是的,我已經放棄了重寫的抓取,謝謝你,我總是困惑,爲什麼他使用過濾器,但我現在看到。這正是我的問題,我知道這是具有該功能的東西。我想我需要重新學習過濾器/地圖。謝謝! – Krum110487

+0

Tbh,我根本不會使用'filter' /'map',只是調用'super.then(this._wrapCallback(onFulfilled),this._wrapCallback(onRejected));' – Bergi

+0

同意,我只是意識到我對filter/map有一個基本的誤解,因爲我很少使用它們,知道null被刪除會幫助我理解發生了什麼。 – Krum110487