我有两个JS函数。一个打电话给另一个。在调用函数中,我想调用另一个函数,等待该函数完成,然后继续。因此,例如/伪代码:

function firstFunction(){
    for(i=0;i<x;i++){
        // do something
    }
};

function secondFunction(){
    firstFunction()
    // now wait for firstFunction to finish...
    // do something else
};

我想出了这个解决方案,但不知道这是否是一个聪明的方法。

var isPaused = false;

function firstFunction(){
    isPaused = true;
    for(i=0;i<x;i++){
        // do something
    }
    isPaused = false;
};

function secondFunction(){
    firstFunction()
    function waitForIt(){
        if (isPaused) {
            setTimeout(function(){waitForIt()},100);
        } else {
            // go do that thing
        };
    }
};

这合法吗?有没有更优雅的处理方式?也许是用jQuery?


当前回答

承诺的唯一问题是IE不支持它们。Edge可以,但IE 10和11还有很多:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise(兼容性在底部)

JavaScript是单线程的。如果您没有进行异步调用,那么它的行为将是可预测的。在执行下一个函数之前,主JavaScript线程将按照它们在代码中出现的顺序完全执行一个函数。保证同步函数的顺序是微不足道的——每个函数将完全按照它被调用的顺序执行。

将同步函数视为工作的原子单元。主JavaScript线程将按照语句在代码中出现的顺序完全执行它。

但是,加入异步调用,如下所示:

showLoadingDiv(); // function 1

makeAjaxCall(); // function 2 - contains async ajax call

hideLoadingDiv(); // function 3

This doesn't do what you want. It instantaneously executes function 1, function 2, and function 3. Loading div flashes and it's gone, while the ajax call is not nearly complete, even though makeAjaxCall() has returned. THE COMPLICATION is that makeAjaxCall() has broken its work up into chunks which are advanced little by little by each spin of the main JavaScript thread - it's behaving asychronously. But that same main thread, during one spin/run, executed the synchronous portions quickly and predictably.

我处理它的方法是,就像我说的,函数是功的原子单位。我把函数1和函数2的代码结合在一起——我把函数1的代码放在函数2中,在asynch调用之前。我消去了函数1。包括异步调用在内的所有内容都按顺序可预测地执行。

然后,当异步调用完成时,在主JavaScript线程多次旋转之后,让它调用函数3。这保证了秩序。例如,在ajax中,onreadystatechange事件处理程序被多次调用。当它报告它已经完成时,然后调用你想要的最后一个函数。

我同意这比较乱。我喜欢让代码是对称的,我喜欢让函数做一件事(或接近它),我不喜欢让ajax调用以任何方式负责显示(创建对调用者的依赖)。但是,在同步函数中嵌入异步调用时,为了保证执行顺序,必须做出一些妥协。我必须为ie10编写代码,所以不能保证。

总结:对于同步调用,保证顺序是微不足道的。每个函数都按照被调用的顺序完全执行。对于带有异步调用的函数,保证顺序的唯一方法是监视异步调用何时完成,并在检测到该状态时调用第三个函数。

关于JavaScript线程的讨论,请参见:https://medium.com/@francesco_rizzi/ JavaScript -main-thread- -43c85fce7e23和https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop

另外,关于这个主题还有一个类似的、评分很高的问题:我应该如何调用3个函数,以便一个接一个地执行它们?

其他回答

等待一个函数先完成的一种优雅方法是使用Promises和async/await函数。


首先,创建一个承诺。 我创建的函数将在2s后完成。我使用 setTimeout来演示 指令需要一些时间来执行。 对于第二个函数,您可以使用 异步/等待 等待第一个函数完成的函数 在继续执行指令之前。


例子:

//1. Create a new function that returns a promise function firstFunction() { return new Promise((resolve, reject) => { let y = 0 setTimeout(() => { for (i=0; i<10; i++) { y++ } console.log('Loop completed.') resolve(y) }, 2000) }) } //2. Create an async function async function secondFunction() { console.log('Before promise call.') //3. Await for the first function to complete const result = await firstFunction() console.log('Promise resolved: ' + result) console.log('Next step.') }; secondFunction()


注意:

您可以像resolve()那样简单地解析Promise而不包含任何值。在我的例子中,我用y值解析了Promise,然后可以在第二个函数中使用y值。

我也有同样的问题。 我的解决方案是在async函数的末尾调用第二个函数, 因为你已经在async函数中有了一个For循环, 一旦达到循环条件的最高值,就可以调用第二个函数 你的情况是什么 I = x-1 所以:

function firstFunction(){
  for(i=0;i<x;i++){
     // do something
     if(i === x - 1){
       // do something else or call secondFunction();
     }
  }
}

经过两天的努力,我写下了这篇文章。这是最好的办法 试着这样做:

var recv = -1; async function First_fn() { var answ = await Second_fn(); console.log(answ); recv = -1; } async function Second_fn() { var parm = 1; var adrss = 2; await Third_fn(adrss, parm); // Using the following loop will minimize the waiting time for (let i = 0; i < 180; i++) { if (recv !== -1) { console.log(recv); break; } else { await new Promise(resolve => setTimeout(resolve, 500)); } } return recv; } async function Third_fn(adrss, parm) { //someting to do => result //for example: let result = adrss + parm; recv = result; // recv is global varable } First_fn();

这就是我想到的,因为我需要在一个链中运行几个操作。

<button onclick="tprom('Hello Niclas')">test promise</button>

<script>
    function tprom(mess) {
        console.clear();

        var promise = new Promise(function (resolve, reject) {
            setTimeout(function () {
                resolve(mess);
            }, 2000);
        });

        var promise2 = new Promise(async function (resolve, reject) {
            await promise;
            setTimeout(function () {
                resolve(mess + ' ' + mess);
            }, 2000);
        });

        var promise3 = new Promise(async function (resolve, reject) {
            await promise2;
            setTimeout(function () {
                resolve(mess + ' ' + mess+ ' ' + mess);
            }, 2000);
        });

        promise.then(function (data) {
            console.log(data);
        });

        promise2.then(function (data) {
            console.log(data);
        });

        promise3.then(function (data) {
            console.log(data);
        });
    }

</script>

我想知道为什么没有人提到这个简单的模式?:

(function(next) {
  //do something
  next()
}(function() {
  //do some more
}))

仅仅为了盲目等待而使用暂停是一种糟糕的做法;而包含承诺只会增加代码的复杂性。以OP为例:

(function(next) {
  for(i=0;i<x;i++){
    // do something
    if (i==x-1) next()
  }
}(function() {
  // now wait for firstFunction to finish...
  // do something else
}))

一个小演示-> http://jsfiddle.net/5jdeb93r/