【问题标题】:Calling an API as a non-blocking call JavaScript以非阻塞调用 JavaScript 调用 API
【发布时间】:2018-08-18 04:59:30
【问题描述】:

我正在构建一个类似待办事项列表的功能,当在输入任务字段上按下 Enter 时添加一个任务。 Enter 调用一个 API(添加任务),执行大约需要 200 毫秒。由于这是阻塞调用,它会阻碍我的代码完全执行并影响我的系统的可用性。这是我想要实现的代码示例。

handleChange(事件){

          if (e.key === 'Enter') {

            targetTaskId = e.target.getAttribute("data-downlink")   
            this.props.addTask(this.props.currentProject.id, '', '', taskId, this.props.currentTasks) //this function calls an add Task API which halts my system momentarily

            targetSelector  = targetTaskId
            $('#' + targetSelector).focus()
            this.setState({activeTask: targetSelector})
            highlightActiveComponent(targetTaskId)

   } 

}

//添加任务

   export function addTask (project_id, taskName, taskNotes, upLink, taskList) {
      console.log('Add Task API call', project_id, taskName, taskNotes, upLink)
      return (dispatch) => {
        callApi('tasks?projectId=' + project_id + '&name=' + taskName + '&notes=' + taskNotes + '&upLink=' + upLink, 'post')
          .then(res => {
            console.log('Response new task ', res)
            let newTask = {name: res.name, id: res.id, notes: res.notes, upLink: upLink, projectId: project_id, assignee: 0, completed: 0, tags: [], isLiked: false, stories: [], likes: [], downLink: res.downLink}
            let newTaskList = addTaskToTaskList(taskList, upLink, newTask)
            dispatch(updateTasks({currentTasks: newTaskList}))
            dispatch({ type: 'SET_ACTIVE_TASK_ID', payload: res.id })

          })
      }
   }

//获取

export const API_URL = 'https://clients.rohan.axcelmedia.ca/v1'

export default function callApi (endpoint, method = 'get', body) {
  let headers = {
    'Accept': 'application/json',
    'Content-Type' : 'application/json'
  }

  if (auth.loggedIn()) {
    headers = _.merge(headers, {
      Authorization: `Bearer ${auth.getToken()}`
    })
  }
  return fetch(`${API_URL}/${endpoint}`, {
    headers,
    method,
    body: JSON.stringify(body)
  }).then(response => {

    return response
  }).then(response => response.json().then(json => ({ json, response })))
    .then(({ json, response }) => {
      if (!response.ok) {
        return Promise.reject(json)
      }
      return json
    })
    .then(
      response => response,
      error => error
    )
}

将任务添加到任务列表

    export function addTaskToTaskList(tasks, upLink, newTask){
        updateTaskDownLink(tasks, newTask.upLink, newTask.id)
        updateTaskUpLink(tasks, newTask.downLink, newTask.id)
        if(upLink == 0){
            tasks.unshift(newTask)
            // console.log("Added in the start", tasks)
            return JSON.parse(JSON.stringify(tasks))
        }
        let myIndex = getIndexOfTaskById(tasks, upLink)
        console.log("Added the new task from helper", myIndex)
        if (myIndex) {
          console.log("Added the new task")
          tasks.splice(myIndex + 1, 0, newTask);
          // console.log("New Task List", JSON.parse(JSON.stringify(tasks)))
        }

        return JSON.parse(JSON.stringify(tasks))
    }

  export function updateTaskUpLink(tasks, taskId, upLink){
      tasks.forEach(function(element, index) {
        if(element.id == taskId) { element.upLink = upLink }
      });

      return tasks
    }

    export function updateTaskDownLink(tasks, taskId, downLink){
        tasks.forEach(function(element, index) {
            if(element.id == taskId) { element.downLink = downLink }
        });

        return tasks
    }

我的问题是,无论如何以非阻塞方式调用此 API,以便我的代码继续执行,当收到来自 api 的响应时,我的光标以无缝方式移动到新任务。 任何帮助,将不胜感激。谢谢 [编辑]:添加了 fetch 函数来演示异步调用

【问题讨论】:

  • 使addTask 使其 HTTP 请求异步并最有可能使用承诺/回调。
  • javascript 在设计上是异步且非阻塞的,也许您的代码中的其他地方发生了某些事情导致您的应用程序呈现不利?也许在addTaskhighlightActiveComponent 中发生了昂贵的计算
  • @james 是的,昂贵的计算发生在 add 任务中,它调用需要一些时间来处理的 api。我正在使用同构提取,人们建议我改用 axios
  • @RafayShahid 使用 fetch 或 axios 或 xhrhttp 或其他什么都没关系,默认情况下,JS 中的所有 api 调用都是异步的。 js中的同步操作只有一手,而且大部分都是和文件系统操作有关的。
  • @James 好的,所以没有办法让这个调用在 js 中非阻塞?

标签: javascript reactjs nonblocking


【解决方案1】:

您应该使用 Fetch API 之类的东西以非阻塞方式调用 API:

fetch("/api/v1/endpoint/5/", {
    method: "get",
    credentials: "same-origin",
    headers: {
        "Accept": "application/json",
        "Content-Type": "application/json"
    }
}).then(function(response) {
    return response.json();
}).then(function(data) {
    console.log("Data is ok", data);
}).catch(function(ex) {
    console.log("parsing failed", ex);
});

console.log("Ciao!");

在sn-p中显示数据的代码只有在服务器返回一些数据时才会执行。

这意味着在我的示例中,日志“Ciao!”将在“数据正常:...”之前显示

希望这会有所帮助:)

sn-p 的致谢:https://gist.github.com/marteinn/3785ff3c1a3745ae955c

【讨论】:

  • @Odle098 这几乎正是我正在做的事情。在我的实用程序中有一个 fetch 函数,它以基于承诺的方式返回响应。据我所知,isomorphic-fetch 不应该造成这个问题,但我现在很困惑
  • @ZeyadEtman 我正在使用 isomorphic-fetch,它也是基于 promise 的,并且与 axios 类似
  • @RafayShahid 也许您应该将一个函数传递给您的“addTask”方法,然后在 fetch 函数中调用该函数。这样你的新“addTask”不应该返回一些东西
【解决方案2】:

首先return JSON.parse(JSON.stringify(tasks)) 是多余的,你可以直接在那里return tasks,这可能会单独解决你的速度问题。但万一它没有。

您的代码可能会因为这里的这种事情而被阻塞

tasks.forEach(function(element, index) {
  if(element.id == taskId) { element.upLink = upLink }
});

return tasks

您为updateTaskDownLink 迭代tasks 数组,再次为updateTaskUpLink 和可能再次为getIndexOfTaskById,这是很多不必要的迭代。

您应该在地图中构建您的任务,而不是一遍又一遍地搜索一系列任务

tasks = {
  "someTaskId": {
    id: "someTaskId",
    upLink: "uplink stuff",
    downLink: "downlink stuff"
  }
}

这样当你去更新任务时,它真的很简单也很快

tasks[taskId].upLink = upLinktasks[taskId].downLink = downLink

没有迭代,没有阻塞,没有问题。

此外,此数据结构将使getIndexOfTaskById 过时!因为您已经拥有访问该任务所需的密钥!万岁!

如果您想知道如何迭代您的 tasks 结构为类似 see here 的地图

【讨论】:

  • 你真的帮我解决了一个大问题!有人告诉我,forEach 速度可能不是速度慢的因素,我完全忽略了这个事实,但删除这两个冗余的 forEach 会使我的 Enter 立即响应。非常感谢!! :)
猜你喜欢
  • 2013-10-29
  • 2014-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-13
  • 1970-01-01
  • 2012-08-17
  • 2018-06-11
相关资源
最近更新 更多