Javascript 在继续之前等待一个函数完成的正确方法?

Javascript 在继续之前等待一个函数完成的正确方法?,javascript,jquery,delay,pausing-execution,Javascript,Jquery,Delay,Pausing Execution,我有两个JS函数。一个叫另一个。在调用函数中,我想调用另一个函数,等待该函数完成,然后继续。因此,例如/伪代码: function firstFunction(){ for(i=0;i<x;i++){ // do something } }; function secondFunction(){ firstFunction() // now wait for firstFunction to finish... // do some

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

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

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

对于(i=0;i处理异步工作的一种方法是使用回调函数,例如:

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的建议,您现在可以使用箭头函数实现相同的功能。例如:

doSomething()
// the function below will wait until doSomething completes if it is synchronous
doSomethingElse()
const secondFunction = async () => {
  const result = await firstFunction()
  // do something else here after firstFunction completes
}
firstFunction(()=>console.log('huzzah,我完成了!'))


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

另外,最初的问题没有具体提到异步,因此,如果有人感到困惑,如果您的函数是同步的,则调用时会阻塞。例如:

doSomething()
// the function below will wait until doSomething completes if it is synchronous
doSomethingElse()
const secondFunction = async () => {
  const result = await firstFunction()
  // do something else here after firstFunction completes
}
尽管暗示函数是异步的,但我现在处理所有异步工作的方式是使用async/await。例如:

doSomething()
// the function below will wait until doSomething completes if it is synchronous
doSomethingElse()
const secondFunction = async () => {
  const result = await firstFunction()
  // do something else here after firstFunction completes
}

依我看,async/await使您的代码比直接使用承诺(大多数情况下)更具可读性。如果您需要处理捕获错误,请将其与try/catch一起使用。请在此处详细阅读:。

这里似乎缺少一个要点:JavaScript是单线程执行环境。让我们再次查看您的代码,注意我添加了
警报(“此处”)


另一方面,JavaScript 1.7引入了
yield
关键字作为。这将允许在其他同步JavaScript代码流中“戳”异步漏洞()但是,目前浏览器对生成器的支持仅限于Firefox和Chrome,AFAIK。

承诺的唯一问题是IE不支持它们。Edge支持,但还有很多IE 10和11:(底部的兼容性)

因此,JavaScript是单线程的。如果您不进行异步调用,它的行为将是可预测的。主JavaScript线程将在执行下一个函数之前完全执行一个函数,按照它们在代码中出现的顺序。保证同步函数的顺序很简单-每个函数都将在ord中完全执行呃叫,

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

但是,抛出异步调用,如下所示:

showLoadingDiv(); // function 1

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

hideLoadingDiv(); // function 3
这并不能满足您的需要。它会立即执行函数1、函数2和函数3。加载div会闪烁,然后它就消失了,尽管
makeAjaxCall()
已经返回,但ajax调用还没有完成。复杂之处在于
makeAjaxCall()
已将其工作分解为块,这些块由JavaScript主线程的每次旋转一点一点地推进-它的行为是非同步的。但同一个主线程在一次旋转/运行期间,快速且可预测地执行同步部分

因此,我处理它的方式:就像我说的,函数是工作的原子单位。我将函数1和2的代码组合在一起-在异步调用之前,我将函数1的代码放在函数2中。我去掉了函数1。异步调用之前的所有内容都按顺序可预测地执行

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

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

摘要:对于同步调用,保证顺序很简单。每个函数都按照调用顺序完全执行。对于具有异步调用的函数,保证顺序的唯一方法是监视异步调用何时完成,并在检测到该状态时调用第三个函数

有关JavaScript线程的讨论,请参见:和

另外,还有一个关于这个主题的类似的、评价很高的问题:

使用异步/等待:

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

等待一个函数首先完成的一种优雅方法是与函数一起使用


  • 首先,创造一个新的环境。 我创建的函数将在2s后完成。我使用
    设置超时
    以演示 执行指令需要一些时间
  • 对于第二个函数,可以使用 函数,您将
    等待第一个函数完成
    在继续执行说明之前

  • 示例:

    //1.创建一个返回承诺的新函数
    函数firstFunction(){
    返回新承诺((解决、拒绝)=>{
    设y=0
    设置超时(()=>{
    
    对于(i=0;i这就是我想到的,因为我需要在一个链中运行多个操作

    <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>
    
    测试承诺
    函数tprom(mess){
    console.clear();
    var承诺=新承诺(功能(解决、拒绝){
    setTimeout(函数(){
    解决(混乱);
    }, 2000);
    });
    var promise2=新承诺(异步函数(解析,rej
    
    async firstFunction() {
                const promise = new Promise((resolve, reject) => {
                    for (let i = 0; i < 5; i++) {
                        // do something
                        console.log(i);
                        if (i == 4) {
                            resolve(i);
                        }
                    }
                });
                const result = await promise;
            }
    
            second() {
                this.firstFunction().then( res => {
                    // third function call do something
                    console.log('Gajender here');
                });
            }
    
    (function(next) {
      //do something
      next()
    }(function() {
      //do some more
    }))
    
    (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
    }))
    
    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; 
    })