Javascript 我可以依赖非链接的后续订单吗?
众所周知,一个人可以将多个承诺组合成一个链,从而一个接一个地调用Javascript 我可以依赖非链接的后续订单吗?,javascript,promise,Javascript,Promise,众所周知,一个人可以将多个承诺组合成一个链,从而一个接一个地调用oncompleted回调(尽管它们彼此是异步的): 但是,无链的后续承诺又如何呢? 最简单的例子是: Promise.resolve() .then(() => console.log("i will be the first one")) ; Promise.resolve() .then(() => console.log("i will be the second one")) // sure? ;
oncompleted
回调(尽管它们彼此是异步的):
但是,无链的后续承诺又如何呢?
最简单的例子是:
Promise.resolve()
.then(() => console.log("i will be the first one"))
;
Promise.resolve()
.then(() => console.log("i will be the second one")) // sure?
;
我天真的认为,Promise回调通过事件队列(大约类似于setTimeout
中的计时器事件)工作,这样一来,第一个Promise.resolve()
在第二个回调之前将其事件推送到队列中,因此第一个回调将在第二个回调之前被调用
但我不确定是否有任何保证。我可以依赖它吗?或者它是异步乐透?有人知道规格说明了什么吗
更新
你们中的一些人注意到,最简单的例子是无用的,所以我想解释一下我原来的问题
我有一个类,它惰性地初始化另一个类的实例,并为托管实例提供get方法:
class Lazy {
/** @param {Class} T */
constructor(T) { }
/** @returns {Promise.<T>} */
instance() {
// there will be complex async initialization at first call
// and Promise.resolve() at following calls
}
}
class Foo {
on() { }
off() { }
}
/** @type {Lazy.<Foo>} */
let foo = new Lazy(Foo);
foo.instance().then((i) => i.on());
foo.instance().then((i) => i.off());
类延迟{
/**@param{Class}T*/
构造函数(T){}
/**@returns{Promise.}*/
实例(){
//第一次调用时将进行复杂的异步初始化
//和Promise.resolve()进行以下调用
}
}
福班{
关于(){}
off(){}
}
/**@type{Lazy.}*/
设foo=newlazy(foo);
然后((i)=>i.on());
foo.instance().then((i)=>i.off());
最后两行揭示了我的问题-当我不确定on()
是否会在off()之前调用on()
时,很难以这种方式使用Foo
实例
承诺回调通过事件队列工作
这不是真的。回调以先返回先服务的方式工作。启动操作时的顺序并不重要,它们返回的顺序决定了将首先处理哪个操作
在您的示例中,如果“第一个”异步操作比“第二个”异步操作花费更长的时间返回,那么“第二个”将首先处理
显然,这些操作需要多长时间才能返回有很多变量。网络速度、服务器上的负载(或您使用的任何异步服务)、promise引擎的浏览器实现等等。因此您必须假设您不知道这些将在何时处理
为了避免竞态条件,如果您需要某种特定的顺序,那么使用回调/。然后
/等待
/etc以确保它们按该顺序运行。您不能依赖于调用操作的顺序。您的实际问题:
最后两行揭示了我的问题——当我不确定在off()之前是否会调用on()时,很难用这种方式处理foo实例
您不应该依赖此行为,而是应该等待
获取实例,然后缓存它:
async function withInstance() {
let instance = await foo.instance();
await instance.on();
await instance.off(); // guaranteed to be called after `.on`.
}
你问的
您可以依赖作业的执行顺序
如果添加了承诺,则它是规范中的一个引用:
来自单个作业队列的挂起作业记录始终以FIFO顺序启动
注意:如果您有多个上下文(例如,iFrame或Worker之间的不同承诺),则此保证不成立
也就是说,强烈建议不要依赖这样的执行顺序。这可能会对您有所帮助,您为什么要这样做?似乎您正试图摆脱承诺的目的,即允许异步响应。如果您试图获得类似于setTimeout(…,0)
的行为,请使用setTimeout
。如果您想保证订单,请使用async
-wait
。如果您有即时返回的同步事件,请不要使用承诺。确定?
-是的,您可以确定您是否也考虑过const p=Promise.resolve();p、 然后(()=>console.log(“我将是第一个”);p、 然后(()=>console.log(“我将是第二个”)代码>整个问题非常不重要,因为如果没有实际的异步操作,那么首先就不要使用承诺。如果您确实有异步操作,那么完成顺序总是不确定的(除非底层的两个操作以某种方式相互关联)。所以,谁在乎两个Promise.resolve()
调用是否按顺序提供呢。在你的代码中,它永远都不重要。如果是这样的话,就用不同的代码来保证订单!“您不知道这些将在什么时候被处理。”-事实上,您知道,这是由语言规范保证的。不过,依赖它并不是一个好主意。我扩展了我的粗体字,整句话是你必须假设你不知道这些信息何时会被处理。:)@本贾明鲁恩鲍姆
async function withInstance() {
let instance = await foo.instance();
await instance.on();
await instance.off(); // guaranteed to be called after `.on`.
}