Promise 保持待定状态,Returns Null

Promise Stays Pending, Returns Null

我正在处理一个 GraphQL 查询,我试图在其中找到一个独特的模型。但是,没有任何东西得到 returned,因为代码在查询完成之前一直在继续,因此在它期望模型时尝试 return Promise。代码如下所示...

          const findShift = async (date) => {
                console.log("In mutation function")
                const foundShift = await db.shift.findUnique({
                    where: {
                        date: date
                    }
                })
                return foundShift
            }
    
            const foundShift = findShift(date).then( resolved => {
                console.log("printing resolved...")
                console.log(resolved)
                if (resolved.id != 'undefined'){
                    console.log({
                        id: resolved.id,
                        date: resolved.date,
                        allDevices: resolved.allDevices
                    })
                    return foundShift
                }
                else{
                    throw new Error("no shift of that date found!")
                }
            })

console.log 语句使控制台看起来如此...

In mutation function
Promise { <pending> }
prisma:info Starting a postgresql pool with 9 connections.

最终查询只是 returns null。如您所见,我尝试使用 then 并将突变本身放入一个完全不同的函数中,只是为了规避这些异步问题,但无济于事。有人看到解决方法吗?

首先,所有 async 函数 return 一个承诺。异步函数中的 return 值成为该承诺的解析值。因此,async 函数的调用者必须使用 .then() 或 await 从异步函数中获取解析值。没有办法像您尝试的那样“规避”异步性。你可以驯服它使它更有用,但你无法逃避它。因此,您的 async 函数 return 是一个悬而未决的承诺,它最终将解析为您 return 在 async 函数中的任何值。

您可以在另一个答案中阅读有关 async 函数如何工作的更多信息


在尝试对您的代码进行 minimal, reproducible example 时,我将其简化为我用异步模拟代替数据库调用的地方:

function delay(t, v) {
    return new Promise(resolve => setTimeout(resolve, t, v));
}

// simulate asynchronous database operation
const db = {
    shift: {
        findUnique: function(data) {
            return delay(100, { id: 123, date: Date.now(), allDevices: ["iPhone", "Galaxy", "Razr"] });
        }
    }
}

const findShift = async (date) => {
    console.log("In mutation function")
    const found = await db.shift.findUnique({
        where: {
            date: date
        }
    })
    return found;
}

const date = Date.now();

const foundShift = findShift(date).then(resolved => {
    console.log("printing resolved...")
    console.log(resolved);
    if (resolved.id != 'undefined') {
        console.log({
            id: resolved.id,
            date: resolved.date,
            allDevices: resolved.allDevices
        })
        return foundShift
    } else {
        throw new Error("no shift of that date found!")
    }
});

当我在 nodejs 中 运行 时,我得到这个错误:

[TypeError: Chaining cycle detected for promise #<Promise>]

而且,错误是由这行代码引起的:

return foundShift

您正试图从承诺链中 return 已经是该承诺链一部分的承诺。这会产生不允许的循环依赖。

您需要什么 return 您希望父承诺的解析值是什么。因为它看起来像是您在其上方构造的对象,所以我修改了代码来执行此操作。此代码可以是 运行 并且 foundShift 是解析为您的对象的承诺。

function delay(t, v) {
    return new Promise(resolve => setTimeout(resolve, t, v));
}

// simulate asynchronous database operation
const db = {
    shift: {
        findUnique: function(data) {
            return delay(100, { id: 123, date: Date.now(), allDevices: ["iPhone", "Galaxy", "Razr"] });
        }
    }
}

const findShift = async (date) => {
    const found = await db.shift.findUnique({
        where: {
            date: date
        }
    })
    return found;
}

const date = Date.now();

const foundShift = findShift(date).then(resolved => {
    if (resolved.id != 'undefined') {
        let result = {
            id: resolved.id,
            date: resolved.date,
            allDevices: resolved.allDevices
        };
        return result;
    } else {
        throw new Error("no shift of that date found!")
    }
});

// foundShift here is a promise
// to get it's value, you have to use .then() or await on it
foundShift.then(result => {
    console.log("final result", result);
}).catch(e => {
    console.log(e);
});

这里有一些关于承诺的规则可能会有所帮助:

  1. 所有 fn().then()fn().catch() 调用 return 一个链接到 fn() returned 的新承诺。
  2. 所有 async 功能 return 承诺。
  3. 您不能“规避”异步性并以某种方式直接return 异步检索的值。您必须使用回调、事件或 return 承诺(或某种类似的异步机制)才能将异步检索的值传回给调用者。
  4. await 只能在 async 函数内部使用(或在 ESM 模块的顶层)。
  5. 函数中的第一个 await 暂停 async 函数的执行,然后立即 return 向调用者发出未实现的承诺。所以,await 只影响当前函数的流程,而不影响调用者的流程。调用者仍然必须使用 .then()await 来从 async 函数 returns.
  6. 的承诺中获取值
  7. 尽可能尝试,没有办法绕过这些规则(在 Javascript 中,因为它目前在浏览器或 nodejs 中 运行)。