我有两个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?


当前回答

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

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();

其他回答

可以使用Promise

承诺是表示未来未知值的JavaScript构造。它可能是API调用的结果,也可能是失败的网络请求的错误对象。你一定能得到一些东西。

const promise = new Promise((resolve, reject) => {
    // Make a network request
   if (yourcondition=="value") {
      
   } else {
      reject(error);
   }
})

promise.then(res => {
    //if not rejected, code

}).catch(err => {
    //return false; 
})

一个承诺可以拥有

完成——动作成功完成

拒绝——操作失败

未决-两个操作都未完成

已解决——已经完成或被拒绝

我也有同样的问题。 我的解决方案是在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();
     }
  }
}

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

<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>

这里您似乎忽略了重要的一点:JavaScript是一个单线程执行环境。让我们再看一遍你的代码,注意我添加了alert(“Here”):

var isPaused = false;

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

function secondFunction(){
    firstFunction()

    alert("Here");

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

你不需要等待isPaused。当你看到“Here”警告时,isPaused将为false, firstFunction将返回。这是因为你不能从for循环内部“屈服”(//做某事),循环可能不会被中断,必须先完全完成(更多细节:Javascript线程处理和竞争条件)。

也就是说,您仍然可以使firstFunction内部的代码流是异步的,并使用回调或承诺通知调用方。你必须放弃for循环,用if (JSFiddle)来模拟它:

function firstFunction()
{
    var deferred = $.Deferred();

    var i = 0;
    var nextStep = function() {
        if (i<10) {
            // Do something
            printOutput("Step: " + i);
            i++;
            setTimeout(nextStep, 500); 
        }
        else {
            deferred.resolve(i);
        }
    }
    nextStep();
    return deferred.promise();
}

function secondFunction()
{
    var promise = firstFunction();
    promise.then(function(result) { 
        printOutput("Result: " + result);
    });
}

另一方面,JavaScript 1.7引入了yield关键字作为生成器的一部分。这将允许在同步JavaScript代码流中“打孔”异步(更多细节和示例)。然而,浏览器对生成器的支持目前仅限于Firefox和Chrome, AFAIK。

承诺的唯一问题是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个函数,以便一个接一个地执行它们?