我一直理解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>

解决方案 »

  1.   

    执行顺序是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);
                });这样就看出来了
      

  2.   

    你说的是对的。第二个里面的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>
      

  3.   

    因为第一个return了一个promise对象 之后的then是由这个return的promise决定的  而第二个没有  这个你可以看看promise基础 
      

  4.   

    then()不是应该都会返回一个Promise对象吗?为什么还要特意自己new一个Promise
      

  5.   

    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.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);
            }
    });
    }
      

  6.   

    then可以接受promise对象,也可以接受非Promise对象,但是必须会回调函数,若没有回调函数就会忽略这个then的执行。对于你这个问题我认为console执行必然快于promise,因为promise是异步的,而且存于栈内,当然栈内也是依次执行,所以结论是先依次执行同步的代码,后依次执行promise,您看是这样吗?
      

  7.   

    then可以接受promise对象,也可以接受非Promise对象,但是必须会回调函数,若没有回调函数就会忽略这个then的执行。对于你这个问题我认为console执行必然快于promise,因为promise是异步的,而且存于栈内,当然栈内也是依次执行,所以结论是先依次执行同步的代码,后依次执行promise,您看是这样吗?
      

  8.   

    感谢楼主的提问,之前自己也有点迷糊,在查了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>
      

  9.   

    楼主的代码 执行顺序应该是 1 =》2,3(同时)。
    注意看了下,第二个then没有返回 promise, 所以第三个then不会等待就直接执行的。
    2,3同时执行的情况下, 由于2 中有settimeout延时执行,所以延时的输出log。如果需要一个then一个then的跑,每个then都返回一个promise吧。