【问题标题】:Problem with fetch calls and promise chaining获取调用和承诺链接的问题
【发布时间】:2022-03-15 17:49:27
【问题描述】:

**edit: 后端有问题

所以我一直遇到链接承诺的问题。我放弃了 axios 并 async await 回去重新学习基础知识,因为我一定在某个地方犯了一个简单的错误,但我没有运气。希望有人可以看看吗?

我按以下顺序调用以下路由:

  1. /users/register
  2. /users/all
  3. /delete/:id
  4. /users/all

问题是代码应该添加一个用户,然后删除同一个用户,但我会说每 6 个左右调用 1 个,第 2 步和第 4 步(显示所有用户)都显示新添加的用户- 这是不正确的。

但据我所知,我正确地将承诺和调用链接在一起。

我一定遗漏了一些明显的东西,但我真的看不到它。如果我错在哪里,我会很感激第二双眼睛或方向

    function test() {
        fetch(`http://localhost:8080/users/register`, {        **//1**
            method: 'POST',
            mode: 'cors',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({ firstName: 'nick', lastName: 'smith', phone: '01980635243', email: 'nick@hotmail.com', password: '1234567891011', confirmPassword:'1234567891011'})
        })
        .then(res => res.json())
        .then(res => {
            console.log(res);
            return fetch('http://localhost:8080/users/all')    **//2**
        })
        .then(res => res.json())
        .then(res => {
            console.log(res)
            return fetch('http://localhost:8080/users/delete-email/nick@hotmail.com', {  **//3**
                method: 'DELETE',
                mode: 'cors',
                headers: {
                    'Content-Type': 'application/json'
                }
            });
        })
        .then(res => res.json()) 
        .then(res => {
            console.log(res)
            return fetch('http://localhost:8080/users/all');    **//4**
        })
        .then(res => res.json())
        .then(res => console.log(res))
        .catch(err => console.log(err));
    }

【问题讨论】:

  • 它们的链接很好,但是你想保留所有的结果吗?最好不要将它们链接起来并在一个数组和 Promise.all 中将它们全部关闭?
  • 你确定这与 fetch/promises 有什么关系吗?如果最终执行了所有操作,那么服务器对您的 GET 的响应很可能与您预期的不一致。
  • 不完全不,也许它可能在服务器端,但每次我测试单个路由时它似乎都有效。我想至少如果我知道上面的代码是正确的,我可以开始关注它。
  • @evolutionxbox 你不能并行运行这些。它们必须按顺序运行,因为每个 Promise 都取决于前一个操作的结果..
  • 我只是看不到第 4 步如何返回相同数量的数组值 - 我从服务器得到正确的响应,我可以看到它正在被删除 - 所以它肯定有成为一个承诺问题?以上是除了调用test()之外的唯一代码。

标签: javascript promise fetch-api


【解决方案1】:

您可以退后一步,真正专注于学习基础知识。您应该知道fetch 是一个低级接口,按原样使用它是一个菜鸟之举。编程就是让你的生活更轻松。如果需要处理 JSON,让我们写一个 fetchJSON 特化 -

const fetchJson = (url, opts = {}) =>
  fetch(url, { ...opts, headers: 'Content-Type': 'application/json' })
    .then(r => r.json())

即使有我们的助手,我们也不应该直接使用它。通过定义可重用函数,我们的代码变得更具描述性和更易于使用 -

const userList = () =>
  fetchJson(`http://localhost:8080/users/all`)

创建userRegister 函数也很容易 -

const userRegister = (user = {}) =>
  fetchJson
    ( `http://localhost:8080/users/register`
    , { method: "POST", mode: "cors", body: JSON.stringify(user) }
    )

最后是userDelete -

const userDelete = email =>
  fetchJson
    ( `http://localhost:8080/users/delete-email/${email}`
    , { method: "DELETE", mode: "cors" }
    )

现在我们可以把它们放在一起

const test = () =>
  userRegister({
    firstName: 'nick',
    lastName: 'smith',
    phone: '01980635243',
    email: 'nick@hotmail.com',
    password: '1234567891011',
    confirmPassword:'1234567891011'
  })
  .then(user => {
    console.log("registered", user)
    return userList()
  })
  .then(users => {
    console.log("list", users)
    return userDelete("nick@hotmail.com")
  })
  .then(_ =>
    console.log("user deleted")
    return userList()
  })

请注意,我们不会将任何 .catch 附加到 test。这留给调用者决定。我们可以这样运行测试 -

test().then(console.log, console.error)

不要停在那里

你看到.then(something => { console.log(something), ... })的模式了吗?我们可以制作一个通用的 log 函数,让这个意图更加清晰 -

const log = label => data =>
{ console.log(label, data)
  return data
}

const test = () =>
  userRegister({
    firstName: 'nick',
    lastName: 'smith',
    phone: '01980635243',
    email: 'nick@hotmail.com',
    password: '1234567891011',
    confirmPassword:'1234567891011'
  })
  .then(log("registered"))
  .then(_ => userList())
  .then(log("list"))
  .then(_ => userDelete("nick@hotmail.com"))
  .then(log("user deleted"))
  .then(_ => userList())

但是这里有一个不好的做法。 console.log 是一个副作用,如果我们能从 test 中得到 each 承诺的结果,那就太好了。我们可以清楚地看到_ => ... 正在替换 链中前一个promise 的值,并且只有final 的promise 值可供调用者使用。

可以将所有结果附加到一个数组中,并将该数组线程化到每个连续的promise,但这也相当乏味。这尤其是在 asyncawait 很有帮助的地方,因为它们使承诺值在同一范围内可用 -

async function test()
{ const user = await userRegister({
    firstName: 'nick',
    lastName: 'smith',
    phone: '01980635243',
    email: 'nick@hotmail.com',
    password: '1234567891011',
    confirmPassword:'1234567891011'
  })

  const list1 = await userList()

  const delete = await userDelete("nick@hotmail.com")

  const list2 = await userList()

  return [user, list1, deleted, list2] // <- all results
}

现在console.log 已与test 分离,所有承诺值的结果可供调用者使用

test().then(console.log, console.error)

【讨论】:

  • 这如何回答 OP 的问题?
  • 有趣的阅读,谢谢,但我现在只是回到使用 axios 实例。我只是使用 fetch 以便我可以遵循一个非常基本的指南,并确保这不是问题所在!
  • @jfriend00 答案是不要那样使用fetch
  • @NickW axios 是低级别的,与 fetch 完全相同。每次需要发出请求时直接使用axios,都会犯同样的错误。编写 fetch/axios 的特化,就像我在这篇文章中演示的那样,专门用于降低代码出错的可能性。这是因为每次使用 fetchaxios 都需要额外的步骤,这极有可能在代码中引入错误。
  • 在他们的问题中,OP 的代码中有什么“错误”或“错误”?是的,OP 根本没有编写 DRY 代码,但他们的代码实际上并没有错,我认为这与问题相关。而且,实际问题出在服务器端,而不是在这个客户端代码中。我看不出您的答案实际上是如何解决任何问题的。是的,它重组了代码并使其更漂亮,但它实际上修复了什么,因此,回到我的问题 - 如何回答 OP 的问题?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-29
  • 2014-10-15
  • 1970-01-01
  • 2017-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多