我正在学习承诺,所以我决定继续扩展它们。一切正常,除非我很难弄清楚如何在所有功能中保持价值。
我的目标是从这个承诺中找到被调用函数的计数,但是每次调用都会创建一个新函数,而我却无法找到传递值的方法。我尝试添加一个构造函数,它将传递一个值在,但它似乎没有像我期望的那样工作。我认为这是由于我误解了"这个"。
的范围总结一下,我的每个功能" init","添加"并且"承诺"所有预先都应该在"步骤总数和#34;变量,现在在这个例子中是" i"。我希望能够说,我在第3步,第3步,第3步等等......
class Repo {
constructor(setup) {
this.s = {};
this.s._progress = { "total":0, "count":0 };
this.s._logging = { "enabled":true, "location":"console", "pretty":true, "verbose":false, "tabCount":0 };
this.s._remoteInfo = { "name":"", "url":"" };
this.s._localInfo = { "path":"" };
this.s._logReset = () => {
this.s._logging.tabCount = 0;
};
this.s._log = (message, tabCount) => {
if(this.s._logging.enabled) {
let tabs = '';
if(this.s._logging.pretty) {
for(let i = 0; i < tabCount; i++) { tabs = tabs + '\t' };
}
if(this.s._logging.location == 'console') { console.log(tabs, message); }
else {
//TODO: implement the file location to output
}
}
};
this.s._progressReset = () => {
this.s._progress.total = 0;
this.s._progress.count = 0;
};
this.s._addProgressTotal = () => {
this.s._progress.total++;
console.log(this.s._progress.total)
}
this.s._addProgress = () => {
this.s._progress.count++;
console.log('Progress is ' + this.s._progress.count + ' out of ' + this.s._progress.total)
}
}
//Starts the promise chain and passes in the settings to be used.
start() {
this.s._logReset();
this.s._progressReset();
return new RepoPromise((resolve, reject) => {
this.s._log('Start Log: <time>',0)
resolve(this.s);
});
}
}
class RepoPromise extends Promise {
constructor(executor, val) {
let e = executor || function (res, rej) { res('')};
super((resolve, reject) => {
return e(resolve, reject);
});
this.i = val || 0;
}
end() {
const returnValue = super.then((s) => {
return new RepoPromise((resolve, reject) => {
s._log('End Log: <time>',0)
resolve(s);
}, this.i);
});
return returnValue;
}
init() {
//I know I need to add 1 to "i" here, but it won't work
const returnValue = super.then((s) => {
return new RepoPromise((resolve, reject) => {
s._log('git init',1);
s._addProgress();
resolve(s, '')
}, ++this.i);
});
return returnValue;
};
add() {
//I know I need to add 1 to "i" here, but it won't work
const returnValue = super.then((s) => {
return new RepoPromise((resolve, reject) => {
setTimeout(() => {
s._log('git add',1);
s._addProgress();
resolve(s,'');
//reject('Add Failed')
}, Math.random() * (10000 - 1000) + 1000);
},++this.i);
});
return returnValue;
}
commit() {
//I know I need to add 1 to "i" here, but it won't work
const returnValue = super.then((s) => {
return new RepoPromise((resolve, reject) => {
setTimeout(() => {
s._log('git commit -m "message"',1);
s._addProgress();
resolve(s, 'Finished');
}, Math.random() * (5000 - 1000) + 1000);
}, ++this.i);
});
return returnValue;
}
then(onFulfilled, onRejected) {
const returnValue = super.then(onFulfilled, onRejected);
return returnValue;
}
}
用法:
var p = new Repo('')
.start()
.init()
.add()
.commit()
.end()
.catch(
x => {console.log('it broke: ' + x)}
);
答案 0 :(得分:1)
正如您所指出的,链中没有一个承诺,每个then
和catch
都会返回新承诺。因此,请勿尝试保留RepoPromise
中的状态,将其保留在您通过链的对象中作为分辨率值:s
。
将你的第二个参数重新设置为RepoPromise
构造函数:你无法可靠地执行此操作,因为每次调用构造函数时都无法控制。请记住,当您致电then
或catch
时,系统会调用该构造函数。这是在s
上传递价值的另一个原因。 :-)为了完整起见,这里说明了在Promise
内调用构造函数的事实:
class MyPromise extends Promise {
constructor(...args) {
super(...args);
console.log("MyPromise constructor called");
}
}
MyPromise.resolve()
.then(val => val)
.then(val => val)
.then(val => val);
几个旁注:
此:
super((resolve, reject) => {
return e(resolve, reject);
});
可以简单地写成:
super(e);
这没有做任何事情,可以删除:
then(onFulfilled, onRejected) {
const returnValue = super.then(onFulfilled, onRejected);
return returnValue;
}
我对这个问题的理解有点密集,但现在我明白了:您希望每次拨打s._progress.total
/ init
/ add
时增加commit
,在调用每个s._progress.count
/ then
回调时增加catch
。
以下是仅使用then
和catch
而不是添加init
,add
和commit
的简化示例,但您可以轻松地将模式应用于如果你愿意,可以添加它们。
解决方案是将状态跟踪器(s
)保留在promise对象上,并将自己插入创建新promises的各种方式(then
,catch
),以便我们复制追踪从旧承诺到新承诺。我们在所有这些承诺中共享跟踪器,例如,来自根承诺的跟踪器跟踪从那里开始的所有内容。见评论:
"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();
rp.then(delayedGratification) // First chain
.then(delayedGratification)
.then(delayedGratification);
rp.catch(delayedGratification) // Second chain
.then(delayedGratification);
.as-console-wrapper {
max-height: 100% !important;
}