【问题标题】:Custom status change events in JavascriptJavascript 中的自定义状态更改事件
【发布时间】:2020-02-19 02:07:42
【问题描述】:

我有一个执行各种等待任务的异步函数。当函数状态发生变化或其中一项任务完成时,我试图在 React 中通知我的 UI。

const foo = async () => {
    // trigger on load event

    await task1();
    // trigger task1 done event

    await task2();
    // trigger task2 done event

    await task3();
    // trigger on done event
}

我还希望能够为每个事件指定回调,如下所示:

const bar = foo();
foo.on_load(() => {
    // some code goes here
});
foo.on_done(() => {
    // some code goes here
});

另一种选择是这样的:

const bar = foo();
foo.on('status_change', status => {
    // read the status here and do something depending on the status
})

我一直在阅读 JS 中的自定义事件,但不知道如何使用它们。或者也许在 React 中有另一种方法可以做到这一点。

任何想法都会有所帮助。谢谢!

编辑

var uploadTask = storageRef.child('images/rivers.jpg').put(file);

// Register three observers:
// 1. 'state_changed' observer, called any time the state changes
// 2. Error observer, called on failure
// 3. Completion observer, called on successful completion
uploadTask.on('state_changed', function(snapshot){
  // Observe state change events such as progress, pause, and resume
  // Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
  var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
  console.log('Upload is ' + progress + '% done');
  switch (snapshot.state) {
    case firebase.storage.TaskState.PAUSED: // or 'paused'
      console.log('Upload is paused');
      break;
    case firebase.storage.TaskState.RUNNING: // or 'running'
      console.log('Upload is running');
      break;
  }
}, function(error) {
  // Handle unsuccessful uploads
}, function() {
  // Handle successful uploads on complete
  // For instance, get the download URL: https://firebasestorage.googleapis.com/...
  uploadTask.snapshot.ref.getDownloadURL().then(function(downloadURL) {
    console.log('File available at', downloadURL);
  });
});

我试图实现类似上述代码的东西,取自the firebase documentation on uploading files

这是我到目前为止所得到的:

class Task {
  constructor() {
    this.first = null;
    this.second = null;
  }

  on(keyword, callback) {
    switch (keyword) {
      case "first":
        this.first = callback;
        break;
      case "second":
        this.second = callback;
        break;
      default:
        // throw new error
        break;
    }
  }
}

const timeout = async time => {
  return new Promise(resolve => setTimeout(resolve, time));
};

const foo = () => {
  const task = new Task();

  timeout(2000).then(async () => {
    task.first && task.first();
    await timeout(2000);
    task.second && task.second();
  });

  console.log("returning");
  return task;
};

const taskObject = foo();
taskObject.on("first", () => console.log("executing first callback"));
taskObject.on("second", () => console.log("executing second callback"));

有没有更好的方法来做到这一点 - 没有嵌套的 thens?哪种方法更好,什么时候更好? EDIT - 删除嵌套的 then 子句并替换为 thenawait

PS:对于我的要求,有回调就足够了。这只是为了让我更好地理解这个概念。谢谢!

【问题讨论】:

  • 在你的例子中,你为什么不直接调用方法?

标签: javascript reactjs async-await custom-events


【解决方案1】:

我将假设您不是在每个异步步骤完成后简单地调用某个命名方法的原因,即您希望能够为每个事件插入不同的处理程序。这是一种解决方法 - 从所提供的小背景很难判断它是否是最好的:

const foo = async (handlers) => {
  handlers.onLoad && handlers.onLoad();

  await task1();
  handlers.onTask1Complete && handlers.onTask1Complete();

  await task2();
  handlers.onTask2Complete && handlers.onTask2Complete();
}
const myHandlers = {
  onLoad: () => {
    // do stuff
  },
  onTask1Complete: () => {
    // do other stuff
  },
  onTask2Complete: () => {
    // etc
  }
};

foo(myHandlers);

请注意,它只允许您指定所需的处理程序。更灵活的方法是发布-订阅模型,其中订阅方法将函数推送到处理程序数组,所有处理程序在事件发生时被调用。

【讨论】:

  • 是的,这适用于我的用例,只是不确定这是否是正确的方法。对于上下文,我正在尝试上传文件(该函数执行多个异步任务)并且我试图在完成特定任务时通知我的 UI。更好的是,我可以有一个回调并从那里传递函数的状态。
  • 你能看看编辑过的问题并帮助我理解吗?谢谢!
  • @shubhamrawal7 避免嵌套 then 的方法是使用 await - 这正是它的设计目的。
  • 好的,更仔细地阅读代码,我明白你为什么不能使用 await - 因为你直到 foo 返回后才设置处理程序。我总是在调用异步函数之前设置我的处理程序,这可以解决这个特定问题。如果您需要/想要让 foo 返回任务对象,那么您将陷入嵌套的 thens 中,或者至少需要使用 then 解决第一个承诺。
  • 好的,我明白了。我已经更新了我的代码,使其只有一个 then,并将其余逻辑作为异步函数,以防有人发现它有帮助。谢谢。
【解决方案2】:

最好的选择是使用 Promise,这意味着每次 Promise 被解决时,你都会收到通知,然后级联的 Promise 会被执行。

以下链接承诺的示例

var function3 = function(resolve, reject)
{
   try
   {
     //do some thing
     console.log('function3 called');
     resolve('function3 success');
   }
   catch(err)
   {
      reject(err);
   }
}

var function2 = function(resolve, reject)
{
   try
   {
     //do some thing
     console.log('function2 called');
     resolve('function2 success');
     //return new Promise(function3);
   }
   catch(err)
   {
      reject(err);
   }
}

var function1 = function(resolve, reject)
{
   try
   {
     //do some thing
     console.log('function1 called');
     resolve('function1 success');
   }
   catch(err)
   {
      reject(err);
   }
}






var promise = new Promise(function1);

promise
.then(function(response){
  console.log(response);
   return new Promise(function2);
}, function(error)
{
   console.log(error);
})
.then(function(response)
{
  console.log(response);
  return new Promise(function3);
},
function(err)
{
  console.log(error);
})
.then(function(response)
{
  console.log(response);
},
function(err)
{
  console.log(error);
})

//output
"function1 called"
"function1 success"
"function2 called"
"function2 success"
"function3 called"
"function3 success"

【讨论】:

    猜你喜欢
    • 2012-12-04
    • 1970-01-01
    • 2019-05-14
    • 1970-01-01
    • 2018-08-30
    • 2016-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多