[英]What is wrong with my Javascript promise implementation?
I'm trying to build my own Promise to improve my understanding of Promise in javascript.我正在尝试构建自己的 Promise 以提高我对 javascript 中 Promise 的理解。 I'm currently stuck at the
.then
method and I'd like to ask: In the documentation for .then
here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then , it says that the then
method returns a Promise.我目前被困在
.then
方法上,我想问一下:在 .then 的文档中.then
这里的https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise /then ,它表示then
方法返回 Promise。 I'm having difficulties writing this because it seem like this.result
is undefined
.我在写这篇文章时遇到了困难,因为看起来
this.result
是undefined
。 Why is that and how do I fix this?为什么会这样,我该如何解决?
Here's my code:这是我的代码:
class LitePromise {
constructor(fn) {
if (typeof fn !== "function") {
throw new TypeError("Promises have to be functions");
}
this.fn = fn;
this.state = PENDING;
this.result = null;
const resolveCallback = this.resolve.bind(this);
const rejectCallback = this.reject.bind(this);
try {
fn(resolveCallback, rejectCallback);
} catch (err) {
this.reject(err);
}
}
resolve(arg) {
console.log(arg, "arg");
this.result = arg;
this.state = RESOLVED;
}
reject() {
this.state = REJECTED;
}
// make an instance of this promise
then(callback) {
const tinyPromise = new LitePromise(this.fn);
console.log(callback, "callback");
try {
return tinyPromise.resolve(callback(this.result));
} catch {
return tinyPromise.reject(callback(this.result));
}
}
}
console.log("------------------");
const yaypromise = new LitePromise((resolve, reject) => {
console.log("1. running");
setTimeout(() => {
console.log("2. resolving");
resolve("yay");
}, 100);
}).then((result) => {
console.log("3. evaluating");
if (result !== "yay") {
console.log("Is not working yet");
return;
}
console.log("SUCCESS!", result);
});
I think the core issue here is the following.我认为这里的核心问题如下。
then()
typically gets processed in 2 different ways: then()
通常以两种不同的方式处理:
then()
and call those callbacks when the promise gets resolved later .then()
的回调,并在稍后解决 promise 时调用这些回调。 You're never handling case 1, so if the promise resolves after then()
gets called, it won't work.您永远不会处理案例 1,因此如果 promise在
then()
被调用后解析,它将不起作用。
In addition, the sub promise you return from then()
should itself resolve one the result of the callback passed to then()
completes.此外,您从
then()
返回的子 promise 本身应该解决传递给then()
的回调的结果完成。
If this sounds super confusing, it's because it's hard =) I would recommend to try and get your logic right first for just dealing with the callbacks in .then()
, and don't return anything from .then()
yet .如果这听起来非常令人困惑,那是因为这很难 =) 我建议先尝试让您的逻辑正确,以便仅处理.then
.then()
中的回调,并且不要从.then()
返回任何内容。
I also made my own promise for the same reason.出于同样的原因,我还制作了自己的 promise。 It's pretty minimal, maybe it's helpful:
它非常小,也许它有帮助:
https://github.com/evert/promise-demo/blob/master/src/my-promise.js https://github.com/evert/promise-demo/blob/master/src/my-promise.js
Here is a sample program we expect to work with our promise
;这是我们希望与
promise
一起使用的示例程序; note the lowercase p
-注意小写的
p
-
const delay = ms =>
new promise(r => setTimeout(r, ms))
const roll = n =>
{ console.log("rolling...")
return delay(1000)
.then(_ => Math.ceil(Math.random() * n))
.then(x => { console.log(x); return x })
}
const main = _ =>
roll(20).then(x =>
roll(20).then(y =>
roll(20).then(z =>
{ console.log("three rolls:", x, y, z)
return [x,y,z]
}
)
)
)
main()
.then(([x,y,z]) => x + y + z)
.then(sum => console.log("sum:", sum))
.catch(console.error)
rolling...
12
rolling...
18
rolling...
15
three rolls: 12 18 15
sum: 45
As others commented there is a lot to fix in your code.正如其他人评论的那样,您的代码中有很多需要修复的地方。 But don't feel bad as Promise is not particularly easy to implement.
但是不要感觉不好,因为 Promise 并不是特别容易实现。 Here's my first sketch of
promise
.这是我的第一个
promise
草图。 Note value
, resolved
, rejected
are parameters of the constructor but they should be made private.注意
value
、 resolved
、 rejected
是构造函数的参数,但它们应该是私有的。 This can be done using a variety of techniques, but for sake of simplicity I left it this way for now.这可以使用多种技术来完成,但为了简单起见,我暂时保持这种方式。 The caller is only intended to pass the first argument,
exec
-调用者只打算传递第一个参数
exec
-
class promise
{ constructor(exec, value, resolved = false, rejected = false)
{ this.value = value
this.resolved = resolved
this.rejected = rejected
this.callback = []
if (this.resolved || this.rejected) return
exec(x => this.resolve(x), e => this.reject(e))
}
resolve(value)
{ if (this.resolved || this.rejected) return
let p = promise.resolve(value)
for (const [ifResolved, ifRejected] of this.callback)
p = p.then(ifResolved, ifRejected)
Object.assign(this, p)
}
reject(value)
{ if (this.resolved || this.rejected) return
let p = promise.reject(value)
for (const [ifResolved, ifRejected] of this.callback)
p = p.then(ifResolved, ifRejected)
Object.assign(this, p)
}
then(ifResolved, ifRejected = promise.reject)
{ if (this.resolved)
{ try
{ return promise.resolve(ifResolved(this.value)) }
catch (err)
{ return promise.reject(err) }
}
else if (this.rejected)
{ try
{ return promise.resolve(ifRejected(this.value)) }
catch (err)
{ return promise.reject(err) }
}
else
{ this.callback.push([ifResolved, ifRejected])
return this
}
}
catch(ifRejected)
{ return this.then(value => value, ifRejected) }
static resolve(value)
{ return (value instanceof promise)
? value
: new promise(_ => {}, value, true, false)
}
static reject(value)
{ return (value instanceof promise)
? value
: new promise(_ => {}, value, false, true)
}
}
Like Promise, only p.then
, p.catch
should be available on promise
objects.与 Promise 一样,在
promise
对象上应该只有p.then
和p.catch
可用。 We should prevent the user from calling p.resolve
or p.reject
directly, but for now it makes it easy to see how things work.我们应该阻止用户直接调用
p.resolve
或p.reject
,但是现在它可以很容易地看到事情是如何工作的。 The class functions promise.resolve
and promise.reject
are analogous to Promise.resolve
and Promise.reject
. The class functions
promise.resolve
and promise.reject
are analogous to Promise.resolve
and Promise.reject
.
Expand the snippet below to verify the result in your own browser -展开下面的代码片段以在您自己的浏览器中验证结果 -
class promise { constructor(exec, value, resolved = false, rejected = false) { this.value = value this.resolved = resolved this.rejected = rejected this.callback = [] if (this.resolved || this.rejected) return exec(x => this.resolve(x), e => this.reject(e)) } resolve(value) { if (this.resolved || this.rejected) return let p = promise.resolve(value) for (const [ifResolved, ifRejected] of this.callback) p = p.then(ifResolved, ifRejected) Object.assign(this, p) } reject(value) { if (this.resolved || this.rejected) return let p = promise.reject(value) for (const [ifResolved, ifRejected] of this.callback) p = p.then(ifResolved, ifRejected) Object.assign(this, p) } then(ifResolved, ifRejected = promise.reject) { if (this.resolved) { try { return promise.resolve(ifResolved(this.value)) } catch (err) { return promise.reject(err) } } else if (this.rejected) { try { return promise.resolve(ifRejected(this.value)) } catch (err) { return promise.reject(err) } } else { this.callback.push([ifResolved, ifRejected]) return this } } catch(ifRejected) { return this.then(value => value, ifRejected) } static resolve(value) { return (value instanceof promise)? value: new promise(_ => {}, value, true, false) } static reject(value) { return (value instanceof promise)? value: new promise(_ => {}, value, false, true) } } const delay = ms => new promise(r => setTimeout(r, ms)) const roll = n => { console.log("rolling...") return delay(1000).then(_ => Math.ceil(Math.random() * n)).then(x => { console.log(x); return x }) } const main = _ => roll(20).then(x => roll(20).then(y => roll(20).then(z => { console.log("three rolls:", x, y, z) return [x,y,z] } ) ) ) main().then(([x,y,z]) => x + y + z).then(sum => console.log("sum:", sum)).catch(console.error)
I will come back tomorrow to add an example that demonstrates errors and answer any questions if you have them.明天我会回来添加一个示例来演示错误并回答任何问题(如果有的话)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.