我一直理解then().then()是一个chain,每一个then会返回一个promise,然后往后面传。但是我今天跑了一段代码,没有按照这个顺序执行。
在下面这个代码里,先跑了第三个then,然后第一个,再是第二个。可能和setTime有关,但我不明白为什么。
请直接拷贝我的代码,然后保存为html,便可在浏览器里运行,注意我输出的log
<!DOCTYPE html>
<html>
<head>
<title></title>
<script type="text/javascript">
Promise.resolve('foo')
// 1. Receive "foo" concatenate "bar" to it and resolve that to the next then
.then(function(string) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
string += 'bar';
resolve(string);
}, 1);
});
})
// 2. receive "foobar", register a callback function to work on that string
// and print it to the console, but not before return the unworked on
// string to the next then
.then(function(string) {
setTimeout(function() {
string += 'baz';
console.log(string);
}, 1)
return string;
})
// 3. print helpful messages about how the code in this section will be run
// before string is actually processed by the mocked asynchronous code in the
// prior then block.
.then(function(string) {
console.log("Last Then: oops... didn't bother to instantiate and return " +
"a promise in the prior then so the sequence may be a bit " +
"surprising"); // Note that `string` will not have the 'baz' bit of it at this point. This
// is because we mocked that to happen asynchronously with a setTimeout function
console.log(string);
}); </script>
</head>
<body></body>
</html>
在下面这个代码里,先跑了第三个then,然后第一个,再是第二个。可能和setTime有关,但我不明白为什么。
请直接拷贝我的代码,然后保存为html,便可在浏览器里运行,注意我输出的log
<!DOCTYPE html>
<html>
<head>
<title></title>
<script type="text/javascript">
Promise.resolve('foo')
// 1. Receive "foo" concatenate "bar" to it and resolve that to the next then
.then(function(string) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
string += 'bar';
resolve(string);
}, 1);
});
})
// 2. receive "foobar", register a callback function to work on that string
// and print it to the console, but not before return the unworked on
// string to the next then
.then(function(string) {
setTimeout(function() {
string += 'baz';
console.log(string);
}, 1)
return string;
})
// 3. print helpful messages about how the code in this section will be run
// before string is actually processed by the mocked asynchronous code in the
// prior then block.
.then(function(string) {
console.log("Last Then: oops... didn't bother to instantiate and return " +
"a promise in the prior then so the sequence may be a bit " +
"surprising"); // Note that `string` will not have the 'baz' bit of it at this point. This
// is because we mocked that to happen asynchronously with a setTimeout function
console.log(string);
}); </script>
</head>
<body></body>
</html>
.then(function(string) {
console.log(1);
return new Promise(function(resolve, reject) {
setTimeout(function() {
string += 'bar';
resolve(string);
}, 1);
});
})
.then(function(string) {
console.log(2);
setTimeout(function() {
string += 'baz';
console.log(string);
}, 1)
return string;
})
.then(function(string) {
console.log(3);
console.log("Last Then: oops... didn't bother to instantiate and return " +
"a promise in the prior then so the sequence may be a bit " +
"surprising");
console.log(string);
});这样就看出来了
1)请问,多个then表达式难道不应该是依次执行的吗。我的意思是第一个执行完才能执行第二个。我觉得第二个应该是第二个延迟执行完了以后才能执行第三个,这才叫链式啊。现在我感觉几个then是异步的。同时在跑,不是等前一个跑完再跑后面的。
2)另外我还发现,如果在第一个then的settimeout内部打上一个log输出,会发现第一个log并没有延迟,为什么和第二个then情况不一样。<!DOCTYPE html>
<html>
<head>
<title></title>
<script type="text/javascript">
Promise.resolve('foo')
// 1. Receive "foo" concatenate "bar" to it and resolve that to the next then
.then(function(string) {
console.log(1);
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log(11);
string += 'bar';
resolve(string);
}, 1);
});
})
// 2. receive "foobar", register a callback function to work on that string
// and print it to the console, but not before return the unworked on
// string to the next then
.then(function(string) {
console.log(2);
setTimeout(function() {
string += 'baz';
console.log(string);
}, 1)
return string;
})
// 3. print helpful messages about how the code in this section will be run
// before string is actually processed by the mocked asynchronous code in the
// prior then block.
.then(function(string) {
console.log(3);
console.log("Last Then: oops... didn't bother to instantiate and return " +
"a promise in the prior then so the sequence may be a bit " +
"surprising"); // Note that `string` will not have the 'baz' bit of it at this point. This
// is because we mocked that to happen asynchronously with a setTimeout function
console.log(string);
}); </script>
</head>
<body></body>
</html>
这个是别人实现的一个promise,我最近也在学习,你可以参考一下,特别是var ret = isFunction(onFulfilled) && onFulfilled(value) || value; 这一句,好好体会一下 (isFunction是用来判断当前传进来的参数是不是函数的)整个源码在https://github.com/ygm125/promise/blob/master/promise.jsPromise.prototype.then = function(onFulfilled,onRejected){
var promise = this;
// 每次返回一个promise,保证是可thenable的
return Promise(function(resolve,reject){
function callback(value){
var ret = isFunction(onFulfilled) && onFulfilled(value) || value;
if(isThenable(ret)){
ret.then(function(value){
resolve(value);
},function(reason){
reject(reason);
});
}else{
resolve(ret);
}
}
function errback(reason){
reason = isFunction(onRejected) && onRejected(reason) || reason;
reject(reason);
}
if(promise._status === PENDING){
promise._resolves.push(callback);
promise._rejects.push(errback);
}else if(promise._status === FULFILLED){ // 状态改变后的then操作,立刻执行
callback(promise._value);
}else if(promise._status === REJECTED){
errback(promise._reason);
}
});
}
可以回答楼主的问题,也希望后面点进来的同学能获得理解,如果不全面也欢迎补充<!DOCTYPE html>
<html>
<head>
<title></title>
<script type="text/javascript">
Promise.resolve('foo')
//第一个promise已经resolve,将'foo'传入第一个then。
.then(function(string) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
string += 'bar';
resolve(string);
}, 1000);//将1ms改为1s更易观察
});
})
//第一个then中的函数返回一个promise对象,该promise对象状态为pending,
//根据‘如果then中的回调函数返回一个未定状态(pending)的Promise,那么then返回Promise的状态也是未定的,
//并且它的终态与那个Promise的终态相同;同时,它变为终态时调用的回调函数参数与那个Promise变为终态时的回调函数的参数是相同的。
//’摘自MDN。
//直到setTimeout时间到达,调用resolve(string),状态变为fulfilled(resolve),才调用下一个then方法。
.then(function(string) {
setTimeout(function() {
string += 'baz';
console.log(string);
}, 1000)
return string;
})
// 在第二个then中,先调用setTimeout
//(估计题主的问题出在这里,setTimeout调用定时器后不会等待计时完成,而是继续执行下面的代码,
// 在1s的定时结束后再将其中的程序加入任务队列,不理解可以再看看关于MacroTask事件循环相关资料),
// 然后跳到return string,由于setTimeout内代码尚未执行,此时string == 'foobar'。
// 且根据 ‘如果then中的回调函数返回一个值,那么then返回的Promise将会成为接受状态,
// 并且将返回的值作为接受状态的回调函数的参数值。’摘自MDN。
// 因此进入下一个then,且该段代码没有任何延时。
.then(function(string) {
console.log("Last Then: oops... didn't bother to instantiate and return " +
"a promise in the prior then so the sequence may be a bit " +
"surprising");
console.log(string);
});
//由于第二个then中return的string值为'foobar',因此先输出'foobar'。
// 并在前面的1s定时结束后执行string += 'baz', 最后输出foobarbaz。
</script>
</head>
<body>
</body>
</html>
注意看了下,第二个then没有返回 promise, 所以第三个then不会等待就直接执行的。
2,3同时执行的情况下, 由于2 中有settimeout延时执行,所以延时的输出log。如果需要一个then一个then的跑,每个then都返回一个promise吧。