2017-10-16 81 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