promise 执行等待问题?

场景: 页面初始化的时候执行了一个异步fun1,但是时间有点长,假设有3s。 然后页面触发了另一个点击事件fun2,在这个事件中要等待fun1有执行结果后才继续后续。 如何实现这个功能(注意 不是在fun2中在执行一次fun1,而只是等待fun1的执行有结果)

阅读 363
4 个回答

有四种方案推荐使用Promise存储

// 方案1: 使用Promise存储(推荐)
class AsyncManager {
  constructor() {
    this.fun1Promise = null;
  }

  // 页面初始化时调用
  initializePage() {
    // 将异步操作的Promise保存起来
    this.fun1Promise = this.fun1();
  }

  async fun1() {
    console.log('fun1 开始执行...');
    // 模拟3秒的异步操作
    await new Promise(resolve => setTimeout(resolve, 3000));
    console.log('fun1 执行完成');
    return 'fun1的结果';
  }

  async fun2() {
    console.log('fun2 开始执行,等待fun1完成...');
    
    // 等待fun1完成
    if (this.fun1Promise) {
      const result = await this.fun1Promise;
      console.log('fun1结果:', result);
    }
    
    console.log('fun2 继续执行后续逻辑...');
    // 这里写fun2的后续逻辑
  }
}

// 使用示例
const manager = new AsyncManager();

// 页面初始化
manager.initializePage();

// 模拟点击事件(可能在任何时候触发)
setTimeout(() => {
  manager.fun2(); // 1秒后触发,此时fun1还在执行
}, 1000);

setTimeout(() => {
  manager.fun2(); // 4秒后触发,此时fun1已完成
}, 4000);

console.log('='.repeat(50));

// 方案2: 使用状态管理
class StateManager {
  constructor() {
    this.fun1Status = 'pending'; // pending, resolved, rejected
    this.fun1Result = null;
    this.fun1Error = null;
    this.waitingCallbacks = [];
  }

  initializePage() {
    this.executeFun1();
  }

  async executeFun1() {
    try {
      console.log('fun1 开始执行...');
      await new Promise(resolve => setTimeout(resolve, 3000));
      
      this.fun1Result = 'fun1的结果';
      this.fun1Status = 'resolved';
      console.log('fun1 执行完成');
      
      // 执行所有等待的回调
      this.waitingCallbacks.forEach(callback => callback(this.fun1Result));
      this.waitingCallbacks = [];
      
    } catch (error) {
      this.fun1Error = error;
      this.fun1Status = 'rejected';
      this.waitingCallbacks.forEach(callback => callback(null, error));
      this.waitingCallbacks = [];
    }
  }

  waitForFun1() {
    return new Promise((resolve, reject) => {
      if (this.fun1Status === 'resolved') {
        resolve(this.fun1Result);
      } else if (this.fun1Status === 'rejected') {
        reject(this.fun1Error);
      } else {
        // 仍在执行中,添加到等待队列
        this.waitingCallbacks.push((result, error) => {
          if (error) reject(error);
          else resolve(result);
        });
      }
    });
  }

  async fun2() {
    console.log('fun2 开始执行,等待fun1完成...');
    
    try {
      const result = await this.waitForFun1();
      console.log('fun1结果:', result);
      console.log('fun2 继续执行后续逻辑...');
    } catch (error) {
      console.error('fun1执行出错:', error);
    }
  }
}

// 使用示例
const stateManager = new StateManager();
stateManager.initializePage();

setTimeout(() => {
  stateManager.fun2();
}, 1000);

console.log('='.repeat(50));

// 方案3: 简化版全局Promise
let globalFun1Promise = null;

async function fun1() {
  console.log('fun1 开始执行...');
  await new Promise(resolve => setTimeout(resolve, 3000));
  console.log('fun1 执行完成');
  return 'fun1的结果';
}

async function fun2() {
  console.log('fun2 开始执行,等待fun1完成...');
  
  if (globalFun1Promise) {
    const result = await globalFun1Promise;
    console.log('fun1结果:', result);
  }
  
  console.log('fun2 继续执行后续逻辑...');
}

// 页面初始化
function initializePage() {
  globalFun1Promise = fun1();
}

// 使用
initializePage();
setTimeout(() => {
  fun2();
}, 1000);

console.log('='.repeat(50));

// 方案4: 使用EventEmitter模式(适合复杂场景)
class EventManager {
  constructor() {
    this.events = {};
    this.fun1Completed = false;
    this.fun1Result = null;
  }

  on(event, callback) {
    if (!this.events[event]) {
      this.events[event] = [];
    }
    this.events[event].push(callback);
  }

  emit(event, data) {
    if (this.events[event]) {
      this.events[event].forEach(callback => callback(data));
    }
  }

  initializePage() {
    this.executeFun1();
  }

  async executeFun1() {
    console.log('fun1 开始执行...');
    await new Promise(resolve => setTimeout(resolve, 3000));
    
    this.fun1Result = 'fun1的结果';
    this.fun1Completed = true;
    console.log('fun1 执行完成');
    
    // 触发完成事件
    this.emit('fun1Complete', this.fun1Result);
  }

  fun2() {
    console.log('fun2 开始执行,等待fun1完成...');
    
    if (this.fun1Completed) {
      // 如果已经完成,直接继续
      console.log('fun1结果:', this.fun1Result);
      console.log('fun2 继续执行后续逻辑...');
    } else {
      // 如果未完成,监听完成事件
      this.on('fun1Complete', (result) => {
        console.log('fun1结果:', result);
        console.log('fun2 继续执行后续逻辑...');
      });
    }
  }
}

// 使用示例
const eventManager = new EventManager();
eventManager.initializePage();

setTimeout(() => {
  eventManager.fun2();
}, 1000);

加个loading就可以解决,fun1执行时loading=true,执行完成后loading=false,给按钮设置disabled属性,loading=true时disabled=true

  1. Promise 是对象。所以,你可以维护一个队列,保留所有 promise 对象实例。
  2. Promise 的状态只会改变一次,并且有固定的返回值。

所以,你可以这么做:

let firstP
function fun1() {
  firstP = someAsyncFunction();
}
async function fun2() {
  await firstP;
  doNext();
}

不过从 UI 的角度来说,你还是需要及时更新,告知用户状态,避免等太久没响应。

给fun1一个返回状态不就行了,执行前时false,执行后是true。
点击fun2的时候判度状态是否为true,不是的话setInterval循环呗

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题