【问题标题】:Are chained commands always executed in order?链式命令是否总是按顺序执行?
【发布时间】:2015-10-08 16:57:03
【问题描述】:

在 node.js 中编码时(这是异步的),我可以依靠链式命令按顺序执行吗?

var x=new MyObject();
x.start().doAThing().stop()

start 会先运行,然后是 doAThing,然后是 stop

【问题讨论】:

  • 是的,它们总是会按顺序执行。
  • 简短回答:
  • 函数本身将按预期顺序运行,但是,所述函数执行的操作可能不会按预期顺序完成。
  • @KevinB 你能详细说明一下吗?
  • start 将执行,返回,doAThing 将执行,返回,然后 stop 将执行并返回。如果其中任何一个执行异步操作,则异步操作将在一段时间后完成,在所有三个都执行并返回之后。

标签: javascript node.js asynchronous


【解决方案1】:

这取决于这些函数在做什么。除非您使用回调,否则命令将按顺序执行。但是,如果您的 start() 函数的逻辑需要异步调用,则只有在调用完成后才能获得结果。这意味着后续的 doAThing() 函数不能在 start() 函数中使用异步调用的结果。

【讨论】:

  • 回调不会改变执行顺序。改变执行顺序的是 IO 与计算。
  • 是的。通常,IO 命令使用回调将结果发回。但是像 Array.prototype.map() 或 Array.prototype.forEach() 这样的函数会同步使用回调。谢谢指正。
【解决方案2】:

tl;dr 从技术上讲,是的,但是如果链中的某些函数是异步的,您可能需要考虑以不同的方式组织代码。


例如,序列x.start().doAThing().stop() 中的每个方法都是一个方法调用,它需要一些对象来操作。为了调用doAThing(),JavaScript VM 必须首先评估x.start(),然后查找doAThing 函数,然后才能开始执行doAThing 的主体。

doAThing 的作用可能完全不同,具体取决于x.start() 的值!

MyObject.prototype.start = function () {
  if (/* condition */) {
    return {
      doAThing: function () {
        return {
          stop: function () {
            console.log('path1');
          }
        };
      }
    };
  }
  else {
    return {
      doAThing: function () {
        return {
          stop: function () {
            console.log('path2');
          }
        };
      }
    };
  }
};

但是,您的函数可以启动可能发生乱序的异步任务。

MyObject.prototype.start = function () {
  setTimeout(function () {
    // This will happen out-of-order, usually after `stop` returns!
    console.log('timed out');
  }, 0);

  return {
    doAThing: function () {
      return {
        stop: function () {
          console.log('stop');
        }
      };
    }
  };
};

参见jsbin。输出:

stop
timed out

如果您必须链接异步函数,您必须使用回调、承诺或生成器重写代码。例如,使用承诺:

var start = function (obj) {
  return new Promise(function (resolve) {
    setTimeout(function () {
      // This will happen in order.                                            
      console.log('timed out');
      resolve(obj);
    }, 0);
  });
};

var doAThing = function (obj) {
  return Promise.resolve(obj);
};

var stop = function (obj) {
  // Synchronous functions are fine, too.                                      
  console.log('stop');
};

这个链会按顺序执行这些函数:

Promise.resolve(x)
  .then(start)
  .then(doAThing)
  .then(stop);

输出:

timed out
stop

【讨论】:

    【解决方案3】:

    从技术上讲,答案总是肯定的。虽然x.start() 立即触发,但如果它执行 io 操作,Node 的运行时将创建一个线程来执行该操作,因此异步,启动仍然立即触发,x.start().doAThing() 将在x.start() 返回时触发。但是,asynch io 可以在函数返回后返回一个响应,所以如果是异步的,.doAThing() 不会有响应。这就是为什么异步函数使用回调/承诺/ES7 异步函数的原因,技术上也可以使用 ES6 生成器,它可以访问 io 响应。只要不是io操作,Nodejs就是同步的。

    所以

    function start(){
        var a = 1 + 1;
        return {
            doAthing: function(){ return a;}
        };
    }
    

    将完全同步。

    【讨论】:

      猜你喜欢
      • 2010-11-23
      • 2016-02-23
      • 2019-11-15
      • 2018-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多