如何将函数执行顺序设置为在JavaScript中使用回调函数

How to set function execute order to using callback function in JavaScript?

本文关键字:函数 JavaScript 回调 设置 执行 顺序      更新时间:2023-09-26

我想使用回调来处理函数执行顺序。实际上我在学习Node.js,因为它是异步的,所以我很难处理进程。无论如何,有3个函数有回调,

function first(callback){
    console.log("First");
    callback;
}
function second(callback){
    console.log("Second");
    callback;
}

function third(callback){
    console.log("Third");
}
// Let's run it!
first(second(third));
// result 
Second
First

我不明白为什么会有这样的结果。我预期如下:

First
Second
Third

什么问题?我怎么能正确地做呢?在Node.js中,人们通常使用回调来处理函数交换顺序吗?我认为这有点复杂。不是吗?

如其他答案所述,

first(second(third));

这并不像你想象的那样。

我想你真正想做的是:

first(function(){
    second(function(){
        third(function(){
            // ...
        });
    });
});

在ES6(Node 4+)语法中,它将是:

first(() => second(() => third()));

但我更喜欢的是使用Promises 的方法

function first(){
    return new Promise(function(resolve, reject){
        console.log("First");
        resolve();
    });
}
function second(){
    return new Promise(function(resolve, reject){
        console.log("Second");
        resolve();
    });
}
function third(){
    return new Promise(function(resolve, reject){
        console.log("Third");
        resolve();
    });
}

这完全消除了回调,并使实际控制流更有意义:

first()
.then(second)
.then(third);

在promise上签出这篇文章

使用ES7语法(babel/typescript),它就变成了:

async function first(){
    console.log("First");
}
// async function second...
// async function third...
await first();
await second();
await third();

在async/await上签出本文

假设您有两个函数,f和g

当您呼叫f(g())

首先计算g(),以便为f()提供正确的参数

因此,如果您想先执行f(),然后将结果作为参数传递给g,则必须反转流程。

g(f())

不要传递回调链接,而是传递second()执行的结果。您的代码可以写成:

var a = second(third);
first( a );

这应该会让事情变得更清楚:首先执行second(),并将结果(即undefined)作为"回调"传递给first()


此外,这段代码中还有一些语法错误,可能应该是这样的:

function first(callback){
    console.log("First");
    callback();
}
function second(callback){
    console.log("Second");
    callback();
}
function third(callback){
    console.log("Third");
}

使用您的代码,回调永远不会被执行。

正如kajyr所说,如果函数调用中的参数具有()(它告诉函数执行),则它将在实际调用另一个函数之前执行。

要查看此行为,可以在javascript控制台中使用"step-in"逐步执行脚本。Treehouse在使用js控制台方面做了一篇不错的文章。

这里有一个关于跨步、进入等的好解释。

我稍微调整了一下你的代码,不确定这是否适用于你,但这会给你正确的顺序。我只是先接两个电话,然后按顺序给他们打电话。

此外,您需要在var名称后面加上()来执行这些方法。IE:callback();

function first(callback, cb){
    console.log("First");
    callback();
    cb();
}
function second(callback){
    console.log("Second");
}

function third(callback){
    console.log("Third");
}
// Let's run it!
first(second, third);

同样,kajyr有一个正确的答案,我只是给出了另一个解决方案,并为您指明了需要查看它如何独立工作的方向。

如果出于任何原因您不能/不想切换到promise,下面的方法都会起作用。

// -------------------------------------------------------------- //
function f1(callback) {
  setTimeout(() => {
    console.log('f1 complete');
    callback(null);
  }, 500);
}
const f2 = (callback) => {
  setTimeout(() => {
    console.log('f2 complete');
    callback(null);
  }, 300);
};
// -------------------------------------------------------------- //
class RunInOrder {
  constructor(functionArray = [], onComplete = () => {}) {
    this._index = 0;
    this._functionArray = functionArray;
    this._onComplete = onComplete;
    this._runNext();
  }
  _runNext() {
    if (this._index >= this._functionArray.length) {
      return this._onComplete();
    }
    const index = this._index++;
    const fn = this._functionArray[index];
    fn((error) => {
      error && console.error(`[f${index}]`, error);
      this._runNext();
    });
  }
}
// -------------------------------------------------------------- //
new RunInOrder(
  [ f1, f2 ],
  () => console.log('All done.'),
);
// ^^ the above outputs:
// f1 complete
// f2 complete
// All done.