【发布时间】:2019-12-23 04:56:33
【问题描述】:
我是 JS 的新手,我正在尝试了解 Promise 应该如何在幕后工作。 这是一个custom implementation,对我来说看起来相当不错:
class MyPromise {
constructor(executor) {
this._resolutionQueue = [];
this._rejectionQueue = [];
this._state = 'pending';
this._value;
this._rejectionReason;
try {
executor(this._resolve.bind(this), this._reject.bind(this));
} catch (e) {
this._reject(e);
}
}
_runRejectionHandlers() {
while(this._rejectionQueue.length > 0) {
var rejection = this._rejectionQueue.shift();
try {
var returnValue = rejection.handler(this._rejectionReason);
} catch(e) {
rejection.promise._reject(e);
}
if (returnValue && returnValue instanceof MyPromise) {
returnValue.then(function (v) {
rejection.promise._resolve(v);
}).catch(function (e) {
rejection.promise._reject(e);
});
} else {
rejection.promise._resolve(returnValue);
}
}
}
_runResolutionHandlers() {
while(this._resolutionQueue.length > 0) {
var resolution = this._resolutionQueue.shift();
try {
var returnValue = resolution.handler(this._value);
} catch(e) {
resolution.promise._reject(e);
}
if (returnValue && returnValue instanceof MyPromise) {
returnValue.then(function (v) {
resolution.promise._resolve(v);
}).catch(function (e) {
resolution.promise._reject(e);
});
} else {
resolution.promise._resolve(returnValue);
}
}
}
_reject(reason) {
if (this._state === 'pending') {
this._rejectionReason = reason;
this._state = 'rejected';
this._runRejectionHandlers();
while(this._resolutionQueue.length > 0) {
var resolution = this._resolutionQueue.shift();
resolution.promise._reject(this._rejectionReason);
}
}
}
_resolve(value) {
if (this._state === 'pending') {
this._value = value;
this._state = 'resolved';
this._runResolutionHandlers();
}
}
then(resolutionHandler, rejectionHandler) {
var newPromise = new MyPromise(function () {});
this._resolutionQueue.push({
handler: resolutionHandler,
promise: newPromise
});
if (typeof rejectionHandler === 'function') {
this._rejectionQueue.push({
handler: rejectionHandler,
promise: newPromise
});
}
if (this._state === 'resolved') {
this._runResolutionHandlers();
}
if (this._state === 'rejected') {
newPromise._reject(this._rejectionReason);
}
return newPromise;
}
catch(rejectionHandler) {
var newPromise = new MyPromise(function () {});
this._rejectionQueue.push({
handler: rejectionHandler,
promise: newPromise
});
if (this._state === 'rejected') {
this._runRejectionHandlers();
}
return newPromise;
}
}
module.exports = MyPromise;
如您所见,此实现与多线程本身无关,它只是用纯 javascript 编码,没有使用任何 WebAPI。另外,有人说StackOverflow 中内置的 Promise 是在没有多线程的情况下实现的。
这个 MyPromise 在大多数情况下都可以正常工作。但是,在某些情况下,MyPromise 与内置 Promise 的工作方式不同,“为什么?”是我的问题。
这里是有问题的代码sn-p:
new MyPromise((resolve, reject) => {
console.log("first promise");
resolve(1);
}).then((res) => {
console.log("it's in then");
return res+1;
}); console.log("it's in the end");
执行代码吐出“first promise” -> “it's in then” -> “It's in the end”,然而,
new Promise((resolve, reject) => {
console.log("first promise");
resolve(1);
}).then((res) => {
console.log("it's in then");
return res+1;
}); console.log("it's in the end");
另一方面,这会吐出“第一个承诺”->“它在最后”->“它在那个时候”
除非 'then' 方法实现与 'MyPromise.then' 根本不同,否则内置 Promise 的行为看起来不正确。即使考虑到“任务队列”和“事件循环”,我也没有很好地解释为什么存在差异。
我认为 'new Promise(f1).then(f2).then(f3);f4()' 必须按 f1、f2、f3 和 f4 的顺序依次执行,除非它们包含 WebAPI比如里面的 setTimeout 或 $Ajax。但是我的小实验不是这样说的,f1、f4、f2、……你懂的。
'then' 方法是基于某个工作线程还是什么?我完全迷路了。
请给我一些启示。谢谢。
【问题讨论】:
-
在 javascript 中有许许多多的 Promise 实现 - 请参阅 this list - 您可以阅读其他人的代码以了解他们的工作 - 其中一些有源代码,其中包含对部分的引用the promise A+ spec 正在处理中 - 其中一些非常有启发性
-
我在自定义 Promise 中实现的方式是 such。我使用
setInterval来完成这项工作。我不知道它是否更好。并且代码按预期输出。
标签: javascript node.js multithreading promise