promise.then().then()是依次执行的吗?下面的代码为什么没有按顺序执行?

yingShisscWang 2017-03-16 08:32:12
我一直理解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>

...全文
7765 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复 3
1.前端在遇到异步的操作时,不会立即执行它,而是把它放到了异步队列当中,暂缓执行 比如你代码中的return Promise 以及setTimeout 2.setTimeout创建的异步任务的宏任务,promise创建的异步任务是微任务,js开始执行异步任务时,优先执行微任务
<!> 2020-03-23
  • 打赏
  • 举报
回复
https://juejin.im/post/5b7057b251882561381e69bf#heading-5 需要引入任务队列的概念可能比较好理解
king886 2019-02-17
  • 打赏
  • 举报
回复 1
楼主的代码 执行顺序应该是 1 =》2,3(同时)。 注意看了下,第二个then没有返回 promise, 所以第三个then不会等待就直接执行的。 2,3同时执行的情况下, 由于2 中有settimeout延时执行,所以延时的输出log。 如果需要一个then一个then的跑,每个then都返回一个promise吧。
ShenY_J 2018-12-05
  • 打赏
  • 举报
回复 1
感谢楼主的提问,之前自己也有点迷糊,在查了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>
liyaoguang01 2018-04-20
  • 打赏
  • 举报
回复
引用 楼主 yingShisscWang 的回复:
我一直理解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可以接受promise对象,也可以接受非Promise对象,但是必须会回调函数,若没有回调函数就会忽略这个then的执行。对于你这个问题我认为console执行必然快于promise,因为promise是异步的,而且存于栈内,当然栈内也是依次执行,所以结论是先依次执行同步的代码,后依次执行promise,您看是这样吗?
liyaoguang01 2018-04-20
  • 打赏
  • 举报
回复
then可以接受promise对象,也可以接受非Promise对象,但是必须会回调函数,若没有回调函数就会忽略这个then的执行。对于你这个问题我认为console执行必然快于promise,因为promise是异步的,而且存于栈内,当然栈内也是依次执行,所以结论是先依次执行同步的代码,后依次执行promise,您看是这样吗?
Muscle_Mliu 2017-08-01
  • 打赏
  • 举报
回复
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);
       	}
	});
}
似梦飞花 2017-03-17
  • 打赏
  • 举报
回复
因为第一个return了一个promise对象 之后的then是由这个return的promise决定的 而第二个没有 这个你可以看看promise基础
yingShisscWang 2017-03-17
  • 打赏
  • 举报
回复
引用 2 楼 zzgzzg00 的回复:
执行顺序是123 只是2的log延时执行了而已 这样就看出来了
你说的是对的。第二个里面的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>

yingShisscWang 2017-03-17
  • 打赏
  • 举报
回复
引用 4 楼 zzgzzg00 的回复:
因为第一个return了一个promise对象 之后的then是由这个return的promise决定的 而第二个没有 这个你可以看看promise基础
then()不是应该都会返回一个Promise对象吗?为什么还要特意自己new一个Promise
似梦飞花 2017-03-16
  • 打赏
  • 举报
回复
执行顺序是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);
            });
这样就看出来了
yingShisscWang 2017-03-16
  • 打赏
  • 举报
回复
我又跑了一下,打了断点,纠正一下现在的顺序是1-》3->2

87,907

社区成员

发帖
与我相关
我的任务
社区描述
Web 开发 JavaScript
社区管理员
  • JavaScript
  • 无·法
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧