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


当前回答

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

<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 firstFunction(_callback){
    // do some asynchronous work
    // and when the asynchronous stuff is complete
    _callback();    
}

function secondFunction(){
    // call first function and pass in a callback function which
    // first function runs when it has completed
    firstFunction(function() {
        console.log('huzzah, I\'m done!');
    });    
}

根据@Janaka Pushpakumara的建议,你现在可以使用箭头函数来实现同样的事情。例如:

firstFunction(() => console.log('huzzah, I\'m done!'))


更新:我很早就回答了这个问题,真的很想更新它。虽然回调是绝对好的,但根据我的经验,它们往往会导致代码更难阅读和维护。但在某些情况下,我仍然使用它们,例如将进度事件作为参数传递。这次更新只是强调替代方案。

另外,最初的问题并没有特别提到async,所以如果有人感到困惑,如果你的函数是同步的,它将在调用时阻塞。例如:

doSomething()
// the function below will wait until doSomething completes if it is synchronous
doSomethingElse()

如果正如暗示的那样,函数是异步的,那么我现在处理所有异步工作的方式是async/await。例如:

const secondFunction = async () => {
  const result = await firstFunction()
  // do something else here after firstFunction completes
}

在我看来,async/await使你的代码比直接使用promises(大多数时候)更具可读性。如果你需要处理捕获错误,那么使用try/catch。更多信息请点击:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function。

这里您似乎忽略了重要的一点: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。

等待一个函数先完成的一种优雅方法是使用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值。

可以使用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();
     }
  }
}