了解 setTimeout 及其在 JavaScript Promises 中的实现
Understanding setTimeout and its implementation in JavaScript Promises
我有以下代码:
function MyPromise(configFunction) {
let nextSuccessCallBack = undefined;
let nextResolve = undefined;
configFunction(function(message){
setTimeout(function(){
if(nextSuccessCallBack) {
var result = nextSuccessCallBack(message);
if(result && result.then) {
result.then(nextResolve);
} else {
nextResolve && nextResolve(result);
}
}
})
});
return {
then: function(successCallback) {
nextSuccessCallBack = successCallback;
return new MyPromise(function(resolve) {
nextResolve = resolve;
})
}
}
}
new MyPromise(function(resolve, reject) {
resolve('new message');
}).then(function(message) {
console.log(message);
return 'another message'
}).then(function(message) {
console.log(message)
console.log('here')
})
在这个例子中,似乎 nextSuccessCallBack
被设置为 .then
中的回调函数,然后它在 setTimeout 函数中的值现在被填充。然而,这让我很困惑。我认为当我们到达构造函数中的 return
语句时,我们 return 对象并有效地停止函数?如果是这样,那么程序如何到达 setTimeout
?
代码片段中的代码确实解决了这个问题,但是,根据 MDN Uses Promises in JavaScript 更好的代码效率和理解方式,Promise
的错误实现令人困惑。
上面的代码也可以这样写:
const examplePromise = new Promise((resolve, reject) => {
resolve("Another Message");
});
console.log("New Message");
examplePromise.then((message) => {
console.log(message);
});
现在,为了更好地理解 JavaScript 中 Promises 的概念,我再举一个例子:
假设我想创建一个程序,上面写着 hello,然后在 2 秒后说 How Are You?
有两种解决方法
- 只是使用
setTimeout()
函数,在一定时间后执行一个函数
- 使用
setTimeout()
的承诺
案例一(使用 setTimeout()):
console.log("hello"); //Saying hello for the first time
setTimeout(function () {
console.log("How Are You?");
}, 2000); //2000 milliseconds is 2 seconds
案例二(使用Promises)
console.log("hello");
const example = new Promise((resolve) => {
setTimeout(() => {
resolve("How Are You?");
}, 2000);
});
example.then((message) => {
console.log(message);
});
现在,对于像 2 秒后记录消息这样的简单情况,不需要 Promises。您可以使用它们(没问题),但实际上,Promises
用于以下情况:您等待函数执行数据库查询,或者您需要等待服务器给您一些 HTML 响应或者在使用 WebAPIs 等时
P.S: setTimeout()
只是一个例子。 在写一个时一定要使用 setTimeout()
并不是一个规则Promise
。如果您使用 WebAPI 获取数据,您通常会写 $.ajax(...).then(...)
或 fetch(...).then(...)
而不是 setTimeout()
这不是一个正确的 Promise 实现。它显然没有拒绝的能力,而且对于已实现的实现功能,它也不符合 Promises/A+ specification。举两个例子:
不符合规则2.1.2.2
When fulfilled, a promise must have a value, which must not change.
...也不符合规则 2.2.2.3:
If onFulfilled
is a function it must not be called more than once.
在您的实施中,如果您要添加对 resolve
的第二个调用:
new MyPromise(function(resolve, reject) {
resolve('new message'); resolve('new message2');
}).then((function(message) {
console.log(message);
// ... etc
})
...然后对 resolve
的两次调用都会触发 then
回调,并显示承诺值在第一次设置后已被修改。这完全违反了承诺的原则:承诺只能解决一次。
不符合规则2.2.6:
then
may be called multiple times on the same promise.
- If/when
promise
is fulfilled, all respective onFulfilled
callbacks must execute in the order of their originating calls to then
.
如果我们使用下面的代码就不会发生这种情况:
let p = new MyPromise(resolve => resolve("value"));
p.then(console.log); // This callback is called
p.then(console.log); // This callback is not called -> violation!
这些是基本的缺点,这只是冰山一角。
如果您对如何根据 Promise/A+ 实施它感兴趣,请查看 at one I did a few years ago 逐步说明。
关于你的问题
how does the program even get to the setTimeout
?
当您的主代码执行此操作时:
new MyPromise(function(resolve, reject) {
resolve('new message');
})
...然后参数变量 configFunction
使用该回调函数初始化。 MyPromise
构造函数 调用 它,将以下回调作为第一个参数传递给它:
function(message){
setTimeout(function(){
if(nextSuccessCallBack) {
var result = nextSuccessCallBack(message);
if(result && result.then) {
result.then(nextResolve);
} else {
nextResolve && nextResolve(result);
}
}
})
}
所以这意味着你的主代码的回调函数中的 resolve
是用上面的回调函数初始化的。然后你的主代码的回调函数 调用 resolve
带有一个字符串参数。由于 resolve
是上面的回调函数,我们可以看到它被执行时 message
初始化为“新消息”。该函数执行setTimeout
.
我有以下代码:
function MyPromise(configFunction) {
let nextSuccessCallBack = undefined;
let nextResolve = undefined;
configFunction(function(message){
setTimeout(function(){
if(nextSuccessCallBack) {
var result = nextSuccessCallBack(message);
if(result && result.then) {
result.then(nextResolve);
} else {
nextResolve && nextResolve(result);
}
}
})
});
return {
then: function(successCallback) {
nextSuccessCallBack = successCallback;
return new MyPromise(function(resolve) {
nextResolve = resolve;
})
}
}
}
new MyPromise(function(resolve, reject) {
resolve('new message');
}).then(function(message) {
console.log(message);
return 'another message'
}).then(function(message) {
console.log(message)
console.log('here')
})
在这个例子中,似乎 nextSuccessCallBack
被设置为 .then
中的回调函数,然后它在 setTimeout 函数中的值现在被填充。然而,这让我很困惑。我认为当我们到达构造函数中的 return
语句时,我们 return 对象并有效地停止函数?如果是这样,那么程序如何到达 setTimeout
?
代码片段中的代码确实解决了这个问题,但是,根据 MDN Uses Promises in JavaScript 更好的代码效率和理解方式,Promise
的错误实现令人困惑。
上面的代码也可以这样写:
const examplePromise = new Promise((resolve, reject) => {
resolve("Another Message");
});
console.log("New Message");
examplePromise.then((message) => {
console.log(message);
});
现在,为了更好地理解 JavaScript 中 Promises 的概念,我再举一个例子:
假设我想创建一个程序,上面写着 hello,然后在 2 秒后说 How Are You?
有两种解决方法
- 只是使用
setTimeout()
函数,在一定时间后执行一个函数 - 使用
setTimeout()
的承诺
案例一(使用 setTimeout()):
console.log("hello"); //Saying hello for the first time
setTimeout(function () {
console.log("How Are You?");
}, 2000); //2000 milliseconds is 2 seconds
案例二(使用Promises)
console.log("hello");
const example = new Promise((resolve) => {
setTimeout(() => {
resolve("How Are You?");
}, 2000);
});
example.then((message) => {
console.log(message);
});
现在,对于像 2 秒后记录消息这样的简单情况,不需要 Promises。您可以使用它们(没问题),但实际上,Promises
用于以下情况:您等待函数执行数据库查询,或者您需要等待服务器给您一些 HTML 响应或者在使用 WebAPIs 等时
P.S: setTimeout()
只是一个例子。 在写一个时一定要使用 setTimeout()
并不是一个规则Promise
。如果您使用 WebAPI 获取数据,您通常会写 $.ajax(...).then(...)
或 fetch(...).then(...)
而不是 setTimeout()
这不是一个正确的 Promise 实现。它显然没有拒绝的能力,而且对于已实现的实现功能,它也不符合 Promises/A+ specification。举两个例子:
不符合规则2.1.2.2
When fulfilled, a promise must have a value, which must not change.
...也不符合规则 2.2.2.3:
If
onFulfilled
is a function it must not be called more than once.在您的实施中,如果您要添加对
resolve
的第二个调用:new MyPromise(function(resolve, reject) { resolve('new message'); resolve('new message2'); }).then((function(message) { console.log(message); // ... etc })
...然后对
resolve
的两次调用都会触发then
回调,并显示承诺值在第一次设置后已被修改。这完全违反了承诺的原则:承诺只能解决一次。不符合规则2.2.6:
then
may be called multiple times on the same promise.- If/when
promise
is fulfilled, all respectiveonFulfilled
callbacks must execute in the order of their originating calls tothen
.
如果我们使用下面的代码就不会发生这种情况:
let p = new MyPromise(resolve => resolve("value")); p.then(console.log); // This callback is called p.then(console.log); // This callback is not called -> violation!
- If/when
这些是基本的缺点,这只是冰山一角。
如果您对如何根据 Promise/A+ 实施它感兴趣,请查看 at one I did a few years ago 逐步说明。
关于你的问题
how does the program even get to the
setTimeout
?
当您的主代码执行此操作时:
new MyPromise(function(resolve, reject) {
resolve('new message');
})
...然后参数变量 configFunction
使用该回调函数初始化。 MyPromise
构造函数 调用 它,将以下回调作为第一个参数传递给它:
function(message){
setTimeout(function(){
if(nextSuccessCallBack) {
var result = nextSuccessCallBack(message);
if(result && result.then) {
result.then(nextResolve);
} else {
nextResolve && nextResolve(result);
}
}
})
}
所以这意味着你的主代码的回调函数中的 resolve
是用上面的回调函数初始化的。然后你的主代码的回调函数 调用 resolve
带有一个字符串参数。由于 resolve
是上面的回调函数,我们可以看到它被执行时 message
初始化为“新消息”。该函数执行setTimeout
.