我知道承诺的力量,但我有几个同步的旧功能:
function getSomething() {
return someExternalLibrary.functionReturnsAValue()
}
console.log(getSomething()); // eg prints 'foo'
不幸的是,当someExternalLibrary
更新时,它已删除了functionReturnsAValue()
,并将functionReturnsAPromise()
混为一谈:
function getSomething() {
return someExternalLibrary.functionReturnsAPromise()
}
console.log(getSomething()); // now prints '[object]'
当然,这绝对打破了所有写入的东西,这取决于过去的简单值。
显然,我更喜欢两件事:
我读过很多关于为什么承诺很好, ad nauseam 的文章,但简单的事实是:如果我接受承诺,我真正做的就是将代码的其他部分改为承诺,然后必须处理价值的承诺...
有没有办法(在nodejs中)实际等待承诺让自己在一起?
我能找到的最好的就是使用协同程序和屈服,但实际上,它还在推卸责任。为了清楚起见,我希望函数getSomething
继续返回一个值。有办法吗?
显然,我担心我对Promises有些误解......
该应用程序适用于非浏览器实现,仅从命令行运行。我一直试图理解bluebird's reflect()
可能会有什么帮助,但无济于事。
(是的,我知道这个问题已经多次以各种格式提出,但我无法找到核心问题的合适答案。如果有的话,我正在寻找与this question相反。我能找到的最相关(但无益)的问题是:Managing promise dependencies。)
答案 0 :(得分:0)
有发电机功能的概念。这些是语法(星号表示法)和语义中的一种特殊功能。与常规函数不同,生成器函数返回的东西也是ECMAScript的新东西:迭代器。迭代器恰好是专门用于迭代的对象,例如,迭代器。与循环的全新...它们也可以通过调用它们的“下一个”方法手动迭代。每个这样的调用都会产生一个包含两个属性的对象:'value'(迭代器的当前值)和'done'(一个布尔值,表示我们是否达到了iterable的最后一个值)。但是,关于生成器函数的最好的事情是它们能够在每次遇到关键字“yield”时暂停执行。让我们一起看看它们如何协同工作:
'use strict';
let asyncTask = () =>
new Promise((resolve, reject) => {
if (Math.random() > 0.5) {
resolve(1);
} else {
reject(new Error('Something went wrong'));
}
});
let makeMeLookSync = fn => {
let iterator = fn();
let loop = result => {
!result.done && result.value.then(
res => loop(iterator.next(res)),
err => loop(iterator.throw(err))
);
};
loop(iterator.next());
};
makeMeLookSync(function* () {
try {
let result = yield asyncTask();
console.log(result);
} catch (err) {
console.log(err.message);
}
});
答案 1 :(得分:0)
我被反复告知:你无法撤销已被宣告的功能。
ES2017(虽然仍然是草案)似乎在使宣传的代码更易于使用方面取得了很大进展: https://ponyfoo.com/articles/understanding-javascript-async-await
似乎还有一个节点库可以为这种支持做好准备:https://github.com/normalize/mz。
使用这种方法,让apis转换为Promises不会那么糟糕(虽然看起来仍然会使代码库的其余部分中毒):
const fs = require('mz/fs')
async function doSomething () {
if (await fs.exists(__filename)) // do something
}
这个答案的其余部分只是对问题的一般性评论。
让我们从一个传统的同步代码样本开始,有三种来自更多老式'到了更新的':
这是传统的javascript方式,需要基于异常的编程来处理意外错误:
function getSomething() {
if (someproblem) throw new Error('There is a problem');
return 'foo';
}
然而,添加try/ catch
语句变得非常费力且乏味,非常快。
随着node.js的出现,回调变得流行,很好地避开了这个问题,因为每个调用者都明确被迫在同一个回调中处理错误条件。这意味着调用者代码中的错误更少:
function getSomething(callback) {
if (callback) {
if (someproblem)
callback(new Error('There is a problem'), null);
else
callback(null, 'foo');
}
return 'foo';
}
然后,经过一些出牙问题,node.js迅速证明了自己的服务器端通信,人们对异步解决方案提供的速度感到惊讶。像Express和Meteor这样的节点应用程序框架越来越多,重点关注这一点。
不幸的是,使用相同的回调方案很快就变得很麻烦,处理异步代码的开发人员开始使用Promises来努力线性化代码,使其可读,就像传统的(try / catch)代码一样。
问题在于它过于依赖。每个人都开始认为Promise是要走的路。就个人而言,我称之为代码库中的毒药。一旦你拥有使用Promises的任何,你的整个代码库就必须变为异步。恕我直言,这并不总是明智的,也不是切实可行的解决方案。
所有副作用中最糟糕的是上述函数即使完全同步也可以用Promises编写:
var bluebird = require('bluebird');
function getSomething() {
// IMHO, this is ridiculous code, but is increasingly popular.
if (someproblem) return Promise.reject(new Error('There is a problem'));
return Promise.resolve('foo');
}
对于那些怀疑这是一个问题的人,或许应该看看SO问题:How do I convert an existing callback API to promises?。特别注意#3,节点式回调。
所以,对于任何关心的人,我想建议需要一个“避孕药”。为了承诺。我敦促我们需要的不仅仅是承诺:我们需要结果,有时需要及时。
查看默认的node.js api。它不使用Promises。它也提供对api的适当部分的同步和异步调用(例如文件系统)。
对于那些想要倾向于回答这个问题的人:这是你的特权,但是当Promise 不答案的时候有明显的问题,我强烈认为有些情况我们需要能够重新同步解耦代码。
我也为这篇博客文章道歉'风格回答。