最近向我展示了一段代码,这些代码是在全栈开发人员访谈中被要求的。 它涉及创建一个Promise,候选人应在其中执行, 向其传递一个resolve函数,然后链接2个。
我试图非常天真地实现Promise只是为了使代码正常工作。 创建了一个接受解析器功能的ctor, 创建了一个then函数,该函数接受回调并返回Promise, 并只需在resolver函数上调用回调。
class MyPromise {
constructor(resolver) {
this.resolver = resolver;
}
then(callback) {
const result = new MyPromise(callback);
this.resolver(callback);
return result;
}
}
promise = new MyPromise(
(result) => {
setTimeout(result(2), 500);
});
promise.then(result => {
console.log(result);
return 2 * result;
}).then(result => console.log(result));
预期结果为2,4-就像在真正的Promise上运行一样。 但是我得到了2,2。 我在弄清楚如何获取第一个“ then”的返回值并将其传递时遇到麻烦。
答案 0 :(得分:3)
这是创建诺言类的简化代码,
class MyPromise {
constructor(executor) {
this.callbacks = [];
const resolve = res => {
for (const { callback } of this.callbacks) {
callback(res);
}
};
executor(resolve);
}
then(callback) {
return new MyPromise((resolve) => {
const done = res => {
resolve(callback(res));
};
this.callbacks.push({ callback: done });
});
}
}
promise = new MyPromise((resolve) => {
setTimeout(() => resolve(2), 1000);
});
promise.then(result => {
console.log(result);
return 2 * result;
}).then(result => console.log(result));
答案 1 :(得分:2)
您的问题有一些问题:
r2
变量未定义。我会假设使用result
。setTimeout
无济于事,因为您立即执行result(2)
。我会假设使用setTimeout(() => result(2), 500)
。如果在采访中确实给出了这样的代码,那么在做其他事情之前指出这两个问题将是您的工作。
您尝试进行操作时遇到的一个问题是,then
方法(即result
)返回的承诺从未得到解决。您需要尽快解决this
承诺,并使用then
回调返回的值来解决它。
此外,promise构造函数参数是一个应立即执行的函数。
在以下解决方案中,与正确的Promise行为相比,进行了一些简化。
then
回调; then
呼叫; then
回调返回诺言的特殊情况
console.log("Wait for it...");
class MyPromise {
constructor(executor) {
executor(result => this.resolve(result));
}
resolve(value) {
this.value = value;
this.broadcast();
}
then(onFulfilled) {
const promise = new MyPromise(() => null);
this.onFulfilled = onFulfilled;
this.resolver = (result) => promise.resolve(result);
this.broadcast();
return promise;
}
broadcast() {
if (this.onFulfilled && "value" in this) this.resolver(this.onFulfilled(this.value));
}
};
// Code provided by interviewer, including two corrections
promise = new MyPromise(
(result) => {
setTimeout(()=>result(2), 500); // don't execute result(2) immediately
});
promise.then(result => {
console.log(result); // Changed r2 to result.
return 2 * result;
}).then(result => console.log(result));
请注意输出中有500ms的延迟,这是(更正的)setTimeout
代码所期望的。
答案 2 :(得分:2)
那很简单:
const SimplePromise = function(cb) {
cb(
data =>
(this.data = data) &&
(this.thenCb || []).forEach(chain => (this.data = chain(this.data))),
error =>
(this.error = error) &&
(this.catchCb || []).forEach(chain => (this.error = chain(this.error)))
);
this.then = thenCb =>
(this.thenCb = [...(this.thenCb || []), thenCb]) && this;
this.catch = catchCb =>
(this.catchCb = [...(this.catchCb || []), catchCb]) && this;
};
答案 3 :(得分:0)
暗示此r2实际上是结果参数。 代码的问题是您不从result(2)中检索结果。执行第一个“ then”,打印2,返回4,但是这4被浪费了。 我编写了一些具有同步功能的代码,只是为了演示如何获取此2,4输出:
class MyPromise {
constructor(resolver) {
this.resolver = resolver;
}
then(callback) {
var res = callback(this.resolver());
var result = new MyPromise(() => { return res; });
return result;
}
}
let promise = new MyPromise(
() => {
return 2;
});
promise
.then(result => {
console.log(result);
return 2 * result;
})
.then(result => {
console.log(result);
});
如果希望解析器稍微异步,则应使用Promises(因为可以检索在setTimeout内部执行的函数的返回值,请参见 here。
如果不允许您使用这些内置的Promises,则可以自己编写一些虚拟的延迟对象,然后等待它们(setInterval)进行解析(基本上是相同的逻辑)。
答案 4 :(得分:0)
您的原始代码存在一些问题。值得注意的是,您仅在调用then
方法时执行构造函数参数,而实际上并没有链接'then'回调的输出。
这是基于调整您的示例的非常(非常!)基本promise实现。它也适用于在解决承诺后调用“ then”的情况(但如果已经调用了“ then”,则不适用-不支持多个then块)。
class MyPromise {
constructor(resolver) {
let thisPromise = this;
let resolveFn = function(value){
thisPromise.value = value;
thisPromise.resolved = true;
if(typeof thisPromise.thenResolve === "function"){
thisPromise.thenResolve();
}
}
if (typeof resolver === "function") {
resolver(resolveFn);
}
}
then(callback) {
let thisPromise = this;
thisPromise.thenFn = callback;
return new MyPromise((resolve) =>{
thisPromise.thenResolve = () => {
thisPromise.value = thisPromise.thenFn(thisPromise.value);
resolve(thisPromise.value);
}
//automatically resolve our intermediary promise if
//the parent promise is already resolved
if(thisPromise.resolved){
thisPromise.thenResolve();
}
});
}
};
//test code
console.log("Waiting for Godot...");
promise = new MyPromise((resolve) =>{
setTimeout(()=>{
resolve(2)
},500);
});
promise.then((result) => {
console.log(result);
return 2 * result;
}).then((result) => {
console.log(result);
return 2 * result;
}).then((result) => {
console.log(result)
});