我正在尝试学习一些关于Node和异步编程的知识.我读到了Promises,并试图在一个小项目中使用它们,这个项目将用户的帖子从服务A复制到服务B.我在理解如何最好地在Promises之间传递状态时遇到一些麻烦
该项目是使用Promise库为NodeJS编写的
我当前问题的一个简单定义是:
这是一些伪代码,说明了我如何将Promise链接在一起.
Promise.from('service_A_username')
.then(getServiceAUserIdForUsername)
.then(getServiceAPostsForUserId)
.then(function(serviceAPosts) {
// but what? store globally for access later?
doSomethingWith(serviceAPosts);
return Promise.from('service_B_username');
})
.then(getServiceBUserIdForUsername)
.then(getServiceBPostsForUserId)
.done(function(serviceBPosts) {
// how do we interact with Service A posts?
doSomethingThatInvolvesServiceAPostsWith(serviceBPosts);
});
Run Code Online (Sandbox Code Playgroud)
我想过要做的一些事情:
还有其他选择,建议采用什么方法?
我对ES6 Promises和PEP3148期货的实施差异进行推理有点困惑.在Javascript中,当Promise与另一个Promise一起解决时,"outer"promise会在解决或拒绝后继承"内部"promise的值.在Python中,"外部"的未来会立即用"内在的"未来来解决,而不是它的最终价值,这就是问题所在.
为了说明这一点,我为两个平台提供了两个代码片段.在Python中,代码如下所示:
import asyncio
async def foo():
return asyncio.sleep(delay=2, result=42)
async def bar():
return foo()
async def main():
print(await bar())
asyncio.get_event_loop().run_until_complete(main())
Run Code Online (Sandbox Code Playgroud)
在Javascript中,完全等效的代码是这样的:
function sleep(delay, result) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(result);
}, delay * 1000);
});
}
async function foo() {
return sleep(2, 42);
}
async function bar() {
return foo();
}
(async function main() {
console.log(await bar());
})();
Run Code Online (Sandbox Code Playgroud)
sleep 为完整起见而提供的功能.
42正如预期的那样打印Javascript代码.Python代码打印<coroutine object foo at 0x102a05678>和关于"coroutine'foo'的投诉从未等待过".
通过这种方式,JS允许您选择控制将在当前执行上下文中消失的时间点,立即执行awaitpromises,或让调用者等待它们.Python总是让你没有其他选择,而不是总是awaitFuture/coroutine,因为否则你将不得不用一个丑陋的包装器函数在循环中展开Future链,如下所示: …
在使用promises进行编码时,在一系列承诺中访问很久以前的数据是正确的模式是什么?
例如:
do_A.then(do_B).then(do_C).then(do_D).then(do_E_WithTheDataComingFrom_A_And_C_OnlyWhen_D_IsSuccesfullyCompleted)
Run Code Online (Sandbox Code Playgroud)
我目前的解决方案:通过链路传递单个JSON结构,并让每个步骤填充它.有什么意见吗?
以下是我正在处理的典型承诺函数.
var _delete = function(t, id) {
return Promise.cast(Event.find({where: {id: id}}, {transaction: t}))
.then(function(d){
if (d) {
// ------- (*)
return Promise.cast(d.updateAttributes({status: -1}, {transaction: t}))
.then(function(){
// do inventory stuff
return Promise.cast(Inventory.update({}).exec())
.then(function(d){
// do something
})
}).then(function(){
// do product stuff
return Promise.cast(Product.update({}).exec())
.then(function(d){
// do something
})
})
} else {
return Promise.reject('this transaction list does not exist');
}
});
};
Run Code Online (Sandbox Code Playgroud)
这看起来不错,直到我处理更复杂的更新/创建代码将变得非常混乱.
目前我正在做的承诺是1.我有很多无用的返回真实语句,唯一的目的是转到下一个.然后声明2. promise以嵌套方式编程.输入参数通常很复杂,并且有超过1个参数,所以我不能做这样的事情
.then(fun1).then(fun2)
......等
这使我无法'tap'使用.then语句启用/禁用功能.
所以我的问题是如何正确地做到这一点?谢谢..
以下是我所说的非常丑陋的事情....
var _process = function(t, tid) …Run Code Online (Sandbox Code Playgroud) 我想在序列中处理许多承诺.我在下面有一段工作代码,但我想知道我是否过度复杂了承诺的链接.我似乎正在创造大量新的封闭装置,我想知道我是否遗漏了一些东西.
有没有更好的方法来编写此函数:
'use strict';
addElement("first")
.then(x => {return addElement("second")})
.then(x => { return addElement("third")})
.then(x => { return addElement("fourth")})
function addElement(elementText){
var myPromise = new Promise(function(resolve,reject){
setTimeout(function(){
var element=document.createElement('H1');
element.innerText = `${elementText} ${Date.now()}`;
document.body.appendChild(element);
resolve();
}, Math.random() * 2000);
});
return myPromise;
}
Run Code Online (Sandbox Code Playgroud) 我的节点项目当前包含一个嵌套的回调圣诞树,以便获取数据并按正确的顺序处理它们.现在我正在尝试使用Promises重构,但我不确定如何正确地执行它.
假设我正在提取办公室列表,然后为每个办公室提供所有员工,然后是每个员工的工资.最后,所有实体(办公室,员工和工资)应链接在一起并存储在数据库中.
一些伪代码说明了我当前的代码(省略了错误处理):
fetch(officesEndpoint, function (data, response) {
parse(data, function (err, offices) {
offices.forEach(function (office) {
save(office);
fetch(employeesEndPoint, function (data, response) {
parse(data, function (err, employees) {
// link each employee to office
save(office);
save(employee);
employees.forEach(function () {
fetch(salaryEndpoint, function (data, response) {
parse(data, function (err, salaries) {
// link salary to employee
save(employee);
});
});
});
});
});
});
});
});
Run Code Online (Sandbox Code Playgroud)
我尝试用承诺解决这个问题,但我有几个问题:
saveEmployees职能中,我只能访问员工,而不是办公室中的其他办公室:var restClient = require('node-rest-client');
var client = new restClient.Client();
var xml2js = require('xml2js'); …Run Code Online (Sandbox Code Playgroud) 有一些方法,如Q.reduce和Q.all这有助于展平诺言的异类集合的特定情况下诺言链.但请注意,通用案例:
const F = (x) => x;
const a = F(1);
const b = F(2);
const c = F(a + b);
const d = F(a + c);
const e = F(b + c);
console.log(e);
Run Code Online (Sandbox Code Playgroud)
也就是说,每个术语依赖于任意先前定义的术语的一系列赋值.假设这F是一个异步调用:
const F = (x) => Q.delay(1000).return(x);
Run Code Online (Sandbox Code Playgroud)
在没有生成缩进金字塔的情况下,我无法想到表达该模式:
F(100).then(a =>
F(200).then(b =>
F(a+b).then(c =>
F(a+c).then(d =>
F(b+c).then(e =>
F(d+e).then(f =>
console.log(f)
)
)
)
)
)
);
Run Code Online (Sandbox Code Playgroud)
请注意,使用返回的值不起作用:
F(100).then(a => F(200))
.then(b => F(a+b))
.then(c => F(a+c))
.then(d => F(b+c)) …Run Code Online (Sandbox Code Playgroud) 在 ES6 JS 中解构对象时,您可以使用{ a, b }语法从该对象创建新变量,分别调用a和b。但是,据我所知,无法获取对象的键以自动创建具有这些名称的本地范围变量。在下面的例子中,我希望能够使用的假设的伪代码const {} = args;,它会产生const a和const b自动。
const bar = { a: 'apple', b: 'ball' };
const foo = (args) => {
const { a, b } = args;
console.log(a, b); // Great!
const {} = args; // I am aware this isn't valid syntax...
console.log(a, b) // Because of course, it doesn't work.
};
foo(bar);
Run Code Online (Sandbox Code Playgroud)
原因纯粹是因为,在这个 MCVE 之外,我实际上使用了一个带有数十个键的大型对象,我想将其中的某些值传递到 Promise 链的下一部分。我当然可以使用 …
我读到在 Cypress 中我不应该使用它await,也不需要它,因为您可以通过链接删除嵌套。这里我有一个cy.fixure嵌套 incy.origin嵌套 in cy.session,有没有办法把它展平?
cy.session([], () => {
cy.visit("")
cy.origin("https://my-address.com", () => {
cy.fixture("user").then((user) => {
cy.get("#username").type(user.username)
cy.get("#password").type(user.password)
})
cy.get("button[type='submit']").click()
cy.url().should("equal", "/login-success")
})
})
Run Code Online (Sandbox Code Playgroud)
编辑
这不是关于常规 javascript 的问题,它是Cypress特定的,正常的 async/await 在这里不起作用。
我已经阅读了几个使用JavaScript生成器的代码示例,例如这个.我能想到的最简单的生成器使用块是这样的:
function read(path) {
return function (done) {
fs.readFile(path, "file", done);
}
}
co(function *() {
console.log( yield read("file") );
})();
Run Code Online (Sandbox Code Playgroud)
这确实打印出了内容file,但我的挂断是在哪里done调用.看起来,yield是一个语法糖,用于包装它在回调中返回的内容并适当地分配结果值(至少在co将错误参数抛给回调的情况下).我对语法的理解是否正确?
使用done时看起来像什么yield?
javascript ×10
promise ×7
node.js ×4
bluebird ×2
ecmascript-6 ×2
async-await ×1
asynchronous ×1
chaining ×1
co ×1
cypress ×1
future ×1
generator ×1
python ×1
yield ×1