Promise

Promise对象代表暂时不可用的值。

一个已存在的promise引用可以通过不同的方式被接收,如作为异步API的返回值。一旦得到一个promise对象,就可以调用其 then() 方法,以在其值可用时或者出现异常时执行一个动作。

可以通过 new Promise() 方法创建Promise对象,当使用一个已存在的Promise对象时,不需要引入 Promise.jsm 模块。

promise内部状态可为以下三种之一:

  • 未完成状态(pending),此时完成值还不可用,它是唯一一个能够转换为其他状态的状态。
  • 已完成状态(fulfilled),此时完成值可用,完成值与promise永久绑定,可为任意值,包括undefined。
  • 拒绝状态(rejected),出现错误时,拒绝理由与promise永久绑定,可为任意值,包括undefined,一般情况下为 Error 对象。

备注: 使用promise时,应该始终对异常(拒绝理由)进行处理或报告。如果你看见了"A promise chain failed to handle a rejection"的错误信息,你可能就需要检查你的代码。参见下面的 异常处理和常见误区

文档约定

文档规定,完成值的类型通过尖括号内的内容指定。如 OS.File.exists 方法返回一个完成值类型为boolean的promise:

Promise<boolean> exists(string path);

拒绝理由可能在function文档中单独规定,除非特别指定,一般使用 Error 对象作为拒绝理由。

方法概览

Promise then([optional] Function onFulfill, [optional] Function onReject);
Promise catch([optional] Function onReject);

构造函数

创建一个新的promise,初始化为等待状态,并提供解决函数的引用,用于改变其状态。

new Promise(executor);

参数

executor

该函数会马上被调用,它带有两个参数的函数对象:

 

executor(resolve, reject);

构造函数直到执行完成才会返回。解决函数可以在任何时间被调用,在执行过程完成前后都可以,其目标是控制promise的最终状态。如果执行过程抛出异常,异常值会被传递到reject解决函数中。

解决函数

resolve()

用特定值满足绑定的promise,或者把状态传递到一个已存在的promise。如果绑定的promise已经被解决(可能是一个值,也可能是一个rejection,或者是另一个promise),该方法不会做任何事。

备注: 调用该方法时,如果用一个pending状态的promise作为aValue参数,然后在该promise状态改变为fullfilled或者rejected前用另一个值再次调用,第二次调用将不会生效,因为这个绑定的promise已经被pending promise所解决了。

void resolve(
  aValue
);
参数
aValue  可选
如果这个值不是一个promise,包括  undefined, 它会变成绑定promise的实现值。如果这个值是promise,绑定promise会被传递的promise解决,并跟随所提供的promise的状态(包括任何未来的转变)。

reject()

用特定原因拒绝绑定的promise。如果promise已经被解决了,不管是值,拒绝,还是另一个promise,这个方法都不会做任何事。

void reject(
  aReason
);
参数
aReason 可选
绑定promise的拒绝原因。通常是一个 Error 对象,就像在异常处理那样,尽管理由也可以是 undefined。

备注: 该参数不应该是promise。要说明一个被拒绝的promise,应该让拒绝原因等于被拒绝promise自身,而非其拒绝原因。

方法

then()

一旦promise完成或被拒绝,就立即执行一个回调函数,并返回一个新的promise对象,新promise的状态取决于promise和传入的回调函数

回调函数始终会在then返回值后被调用,即使promise早已完成或已被拒绝。也可对多次调用同一个promise的then方法。所有的回调函数会按照其注册的顺序被调用。

 

警告: 如果 onFulfill 抛出异常,不会调用 onReject ,异常也不会被捕获和输出到控制台(你会看到一个promise chain失败错误),可以在返回的promise上注册一个错误处理函数,以处理在任一回调中出现的异常(使用 catch() 或者 then() ),来处理发生在任何一个注册回调函数的异常。

注意:当多次调用同一个promise的then方法,所有注册的回调函数独立执行。如,当在一个回调函数中出现异常时,不会影响后面回调函数的执行。回调函数的结果只会对其注册所使用的then方法返回的promise产生影响,每一次调用then方法返回的都是不同的promise对象。

Promise then(
  Function onFulfill,
  Function onReject
);
参数
onFulfill 可选
当promise完成时,会调用该函数,并将完成值作为其唯一参数传入,该函数的输出会决定新的promise的状态。如果该参数不是函数(通常为null),则由then返回的新的promise的状态为已完成,且完成值与原promise相同
onReject 可选

当promise被拒绝时,会调用该函数,并将拒绝理由作为其唯一参数传入,且该函数的输出会决定新的promise的状态。如果该参数不是函数(通常为undefined),则由then返回的新的promise的状态为拒绝,且拒绝理由与原promise相同。

返回值

新的promise对象,初始状态为未完成,最终状态取决于回调函数的输出:

  • 如果返回的不是promise,包括undefined,则新promise的状态为已完成,并将该返回值作为其完成值,即使原promises被拒绝
  • 如果抛出异常,则新的promise的状态为拒绝,并将该异常作为其拒绝理由,即使原promise已完成
  • 如果返回promise,则新promise的最终状态与回调函数返回的promise状态相同。

catch()

等价于调用onFulfill参数为undefined的 then() 方法。如果你链式调用then( onFulfill ).catch( onReject ),onFulfill中抛出的异常会被捕捉并传递到onReject。

Promise catch(
  Function onReject
);

等价于以下调用:

p.then(undefined, logError);
p.catch(logError);
 

调试

按照设计,在不调用 then()的情况下,promise的即时状态和值不能通过代码同步检测到。

为了有助于调试,只有当手动检查promise时,才能看到那些不能通过代码访问的特殊属性的信息(目前由于缺少复杂的语言或调试器的支持,属性名是随机生成的)。

这些代码可访问和可审查的属性有:

  • {{private:status}}: 0代表未完成,1代表已完成,2代表拒绝。
  • {{private:value}}:完成值或拒绝理由,仅在promise已完成或已拒绝时有值。
  • {{private:handlers}}: 对象数组,这些对象保存了对回调函数的引用,仅在未完成状态下可用。

Promise properties are visible in the debugger.Promise handlers can be watched from the Console.

示例

请看 示例 页面.

异常处理和常见误区

promise应该报告未处理的错误,除非交给其他程序处理该错误。

// ###### WRONG: Silently drops any rejection notified by "OS.File.Exists".
OS.File.exists(path).then(exists => { if (exists) myRead(path); });

// ###### WRONG: Silently drops any exception raised by "myRead".
OS.File.exists(path).then(exists => { if (exists) myRead(path); }, Components.utils.reportError);

// CORRECT (for example, might report the exception "myRead is not defined")
OS.File.exists(path).then(exists => { if (exists) myRead(path); })
                    .then(null, Components.utils.reportError);

// CORRECT (the function returns a promise, and the caller will handle the rejection)
function myReadIfExists(path)
{
  return OS.File.exists(path).then(exists => { if (exists) myRead(path); });
}

参见

文档标签和贡献者

 此页面的贡献者: Zhangjd, hutuxu
 最后编辑者: Zhangjd,