我一直理解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>
uj5u.com熱心網友回復:
我又跑了一下,打了斷點,糾正一下現在的順序是1-》3->2uj5u.com熱心網友回復:
執行順序是123 只是2的log延時執行了而已
Promise.resolve('foo')
.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);
});
這樣就看出來了
uj5u.com熱心網友回復:
你說的是對的。第二個里面的log延遲列印出來了。
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>
uj5u.com熱心網友回復:
因為第一個return了一個promise物件 之后的then是由這個return的promise決定的 而第二個沒有 這個你可以看看promise基礎uj5u.com熱心網友回復:
then()不是應該都會回傳一個Promise物件嗎?為什么還要特意自己new一個Promise
uj5u.com熱心網友回復:
then是會回傳一個promise物件,但是這個promise物件的this是你前一個promise的,如果你return 一個新的promise,this則是這個promise,所以后面的then需要依據第二個promise是否resolve,才決定是否執行相應的then這個是別人實作的一個promise,我最近也在學習,你可以參考一下,特別是var ret = isFunction(onFulfilled) && onFulfilled(value) || value; 這一句,好好體會一下 (isFunction是用來判斷當前傳進來的引數是不是函式的)
整個原始碼在https://github.com/ygm125/promise/blob/master/promise.js
Promise.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);
}
});
}
uj5u.com熱心網友回復:
then可以接受promise物件,也可以接受非Promise物件,但是必須會回呼函式,若沒有回呼函式就會忽略這個then的執行。對于你這個問題我認為console執行必然快于promise,因為promise是異步的,而且存于堆疊內,當然堆疊內也是依次執行,所以結論是先依次執行同步的代碼,后依次執行promise,您看是這樣嗎?uj5u.com熱心網友回復:
then可以接受promise物件,也可以接受非Promise物件,但是必須會回呼函式,若沒有回呼函式就會忽略這個then的執行。對于你這個問題我認為console執行必然快于promise,因為promise是異步的,而且存于堆疊內,當然堆疊內也是依次執行,所以結論是先依次執行同步的代碼,后依次執行promise,您看是這樣嗎?
uj5u.com熱心網友回復:
感謝樓主的提問,之前自己也有點迷糊,在查了mdn和相關資料后基本搞明白了promise和then的原理。下面把樓主的程式全部分析一遍,應該可以回答樓主的問題,也希望后面點進來的同學能獲得理解,如果不全面也歡迎補充
<!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>
uj5u.com熱心網友回復:
樓主的代碼 執行順序應該是 1 =》2,3(同時)。注意看了下,第二個then沒有回傳 promise, 所以第三個then不會等待就直接執行的。
2,3同時執行的情況下, 由于2 中有settimeout延時執行,所以延時的輸出log。
如果需要一個then一個then的跑,每個then都回傳一個promise吧。
uj5u.com熱心網友回復:
https://juejin.im/post/5b7057b251882561381e69bf#heading-5需要引入任務佇列的概念可能比較好理解
uj5u.com熱心網友回復:
1.前端在遇到異步的操作時,不會立即執行它,而是把它放到了異步佇列當中,暫緩執行 比如你代碼中的return Promise 以及setTimeout2.setTimeout創建的異步任務的宏任務,promise創建的異步任務是微任務,js開始執行異步任務時,優先執行微任務
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/76995.html
標籤:JavaScript
上一篇:后端接收不到前端傳的資料
