2017-04-23 134 views
2

我正在嘗試使用承諾一個小的新項目。但是我在理解如何更好地組織我的代碼時遇到了一些問題,並帶有函數。問題是,我想要我的函數來處理事情,我的主要代碼處理其他事情。讓我們看看下面的代碼:承諾與功能鏈接

function doSomething (isGoingToResolve = true) { 
    return new Promise((resolve, reject) => { 
    if (isGoingToResolve) { 
     resolve("something") 
    } else { 
     reject("something else") 
    } 
    }).then(response => { 
    console.log("in my function",response) 
    }).catch(error => { 
    console.log("in my function",error) 
    }) 
} 

doSomething().then(response => { 
    console.log("in my main call", response) 
}) 

有了這個代碼,控制檯將記錄in my function somethingin my main call undefinedhttps://jsfiddle.net/hkacvw2g/

於是我發現了兩個解決方案,以解決我的問題,但我只是不喜歡他們:

第一個是創建一個變量,該變量使用.then(),然後返回變量(https://jsfiddle.net/hkacvw2g/1/):

function doSomething (isGoingToResolve = true) { 
    let promise = new Promise((resolve, reject) => { 
    if (isGoingToResolve) { 
     resolve("something") 
    } else { 
     reject("something else") 
    } 
    }) 

    promise.then(response => { 
    console.log("in my function",response) 
    }).catch(error => { 
    console.log("in my function",error) 
    }) 

    return promise 
} 

並將第二溶液(https://jsfiddle.net/hkacvw2g/2/):

function doSomething (isGoingToResolve = true) { 
    return new Promise((resolve, reject) => { 
    if (isGoingToResolve) { 
     resolve("something") 
    } else { 
     reject("something else") 
    } 
    }).then(response => { 
    console.log("in my function",response) 
    return new Promise(resolve => { 
     resolve(response) 
    }) 
    }).catch(error => { 
    console.log("in my function",error) 
    return new Promise((resolve,reject) => { 
     reject(error) 
    }) 
    }) 
} 

我缺少一個更好的解決方案,以解決我的問題?

+2

關閉話題。我建議你閱讀關於承諾反模式。經驗法則:您幾乎不需要在代碼中手動使用'Promise'構造函數。 http://www.datchley.name/promise-patterns-anti-patterns/ –

+0

感謝您的評論和鏈接,我實際上使用'mysql-promise' npm軟件包,但我想讓我的問題更通用 – Hammerbot

+1

您可能想看看這篇關於承諾鏈接的文章,這篇文章幫助我圍繞這個話題進行了包裝。 HTTP:// solutionoptimist。com/2013/12/27/javascript-promise-chains-2/ – Hinrich

回答

2

您可以簡單地返回值(或重新拋出錯誤),它會在承諾鏈來解決:

function doSomething (isGoingToResolve = true) { 
    return new Promise((resolve, reject) => { 
    if (isGoingToResolve) { 
     resolve("something") 
    } else { 
     reject("something else") 
    } 
    }).then(response => { 
    console.log("in my function",response) 
    return response; 
    }).catch(error => { 
    console.log("in my function",error) 
    throw error; 
    }) 
} 

你可能不希望出現這種情況throw error,這取決於你想如何處理你的拒絕。這樣當你重新拋出錯誤時,你應該在調用doSomething()方法時抓住它。

+0

就這麼簡單,謝謝! (接受10分鐘後的義務) – Hammerbot

+0

其實,我更喜歡他的第一個解決方案。它更健壯。它通過不經意地忘記從僅用於記錄日誌的'then'子句中返回原始值來減少混淆承諾鏈的風險。 – 2017-04-23 11:38:45

1

你可以寫一個tap功能,打入一個承諾鏈,並做一些事情,而沿結果傳球,和並行tapCatch功能,進軍錯誤而重新拋出他們:

const tap  = fn => value => { fn(value); return value; }; 
const tapCatch = fn => reason => { fn(reason); throw reason; }; 

現在你可以寫你的代碼爲:

function doSomething(isGoingToResolve = true) { 
    (isGoingToResolve ? 
    Promise.resolve("something") : 
    Promise.reject("something else") 
) 
    .then(tap  (response => console.log("in my function", response))) 
    .catch(tapCatch(error => console.log("in my function", error))); 
} 

doSomething() 
    .then(response => console.log("in my main call", response)); 

然而,實際上你的第一個解決方案更好。它通過不注意或不意識到必須返回then條款中的原始值或重新拋出catch條款來減少混淆承諾鏈的風險,這些條款僅用於記錄目的或其他副作用。

你也可以污染Promise原型像tap(我們把它叫做thenDo),使得它有點更容易使用:

Promise.prototype.thenDo = function(ifFulfilled, ifRejected) { 
    return this.then(
    value => { ifFulfilled(value); return value; }, 
    reason => { ifRejected(reason); throw reason; }); 
}; 
Promise.prototype.catchDo = function(ifRejected) { 
    return this.catch(reason => { ifRejected(reason); throw reason; }); 
}; 

現在你可以寫

function doSomething(isGoingToResolve = true) { 
    (isGoingToResolve ? 
    Promise.resolve("something") : 
    Promise.reject("something else") 
) 
    .thenDo (response => console.log("in my function", response)) 
    .catchDo(error => console.log("in my function", error)); 
}