JavaScript中异步函数的返回值默认是Promise对象,这和普通同步函数的返回值处理逻辑有很大区别,很多开发者在对象方法中调用异步函数时,容易忽略这个特性,导致后续逻辑无法拿到预期的结果。

异步函数返回值的基本特性
当我们声明一个async函数时,无论函数内部返回的是什么类型的值,这个函数的执行结果都会被包裹成一个Promise对象。如果返回的是普通值,Promise会处于 fulfilled 状态,值就是返回的内容;如果返回的是另一个Promise,那么函数的返回值就是这个Promise本身。
下面通过一个简单的示例来展示这个特性:
// 普通异步函数,返回普通值
async function getNormalValue() {
return 'hello world';
}
// 异步函数返回Promise
async function getPromiseValue() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('promise result');
}, 1000);
});
}
// 调用测试
getNormalValue().then(res => {
console.log(res); // 输出 hello world
});
getPromiseValue().then(res => {
console.log(res); // 1秒后输出 promise result
});
对象方法中调用异步函数的常见错误
很多开发者会在对象的方法中定义异步操作,然后直接调用这个方法,期望直接拿到返回值,这是最常见的错误场景。我们来看一个错误的示例:
const userModule = {
// 对象中的异步方法,获取用户名称
async getUserName() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('张三');
}, 500);
});
},
// 错误调用方式:直接获取返回值
printUserName() {
const name = this.getUserName();
console.log(name); // 输出 Promise { <pending> }
console.log(`用户名称是:${name}`); // 输出 用户名称是:Promise { <pending> }
}
};
userModule.printUserName();
上面的代码中,getUserName是异步方法,返回的是Promise对象,而printUserName方法直接把Promise赋值给name变量,没有等待Promise的状态变更,所以拿到的不是预期的用户名称,而是Promise实例本身。
正确的调用姿势
姿势一:在对象方法中使用await等待异步结果
如果对象的方法本身也是async函数,那么可以在方法内部使用await关键字等待异步方法的返回值,前提是调用环境支持async/await语法。
const userModule = {
async getUserName() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('张三');
}, 500);
});
},
// 正确的调用方式:方法本身声明为async,使用await等待
async printUserName() {
const name = await this.getUserName();
console.log(name); // 500毫秒后输出 张三
console.log(`用户名称是:${name}`); // 输出 用户名称是:张三
}
};
userModule.printUserName();
姿势二:通过then方法处理Promise返回值
如果不想将对象方法声明为异步函数,也可以通过Promise的then方法来处理异步返回值,这种方式兼容性更好,适合不支持async/await的环境。
const userModule = {
getUserName() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('张三');
}, 500);
});
},
// 使用then处理返回值
printUserName() {
this.getUserName().then(name => {
console.log(name); // 500毫秒后输出 张三
console.log(`用户名称是:${name}`); // 输出 用户名称是:张三
});
}
};
userModule.printUserName();
姿势三:处理异步方法中的错误
异步操作可能会出现异常,所以正确的调用还需要包含错误处理,无论是使用await还是then方法,都需要考虑异常情况。
使用await时的错误处理:
const userModule = {
async getUserName() {
return new Promise((resolve, reject) => {
setTimeout(() => {
// 模拟异常情况
const isSuccess = Math.random() > 0.5;
if (isSuccess) {
resolve('张三');
} else {
reject(new Error('获取用户名称失败'));
}
}, 500);
});
},
async printUserName() {
try {
const name = await this.getUserName();
console.log(`用户名称是:${name}`);
} catch (err) {
console.error('发生错误:', err.message);
}
}
};
userModule.printUserName();
使用then方法时的错误处理:
const userModule = {
getUserName() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const isSuccess = Math.random() > 0.5;
if (isSuccess) {
resolve('张三');
} else {
reject(new Error('获取用户名称失败'));
}
}, 500);
});
},
printUserName() {
this.getUserName()
.then(name => {
console.log(`用户名称是:${name}`);
})
.catch(err => {
console.error('发生错误:', err.message);
});
}
};
userModule.printUserName();
注意事项总结
- 异步函数的返回值永远是Promise对象,不能直接当作普通值使用
- 对象方法中调用异步函数时,要么将调用方法声明为async并使用await,要么通过then链式调用处理结果
- 异步操作必须包含错误处理,避免未捕获的异常导致程序崩溃
- 如果异步方法需要访问对象的this上下文,要注意箭头函数和普通函数的this指向差异,避免this丢失
在实际开发中,建议优先使用async/await的写法,代码逻辑更清晰,可读性更强,同时不要忘记搭配try/catch处理异常情况。
JavaScriptPromise异步函数对象方法修改时间:2026-07-08 14:39:35