JavaScript异步编程Promise模式的6个特性

作者:木棉时间:2026-10-28 08:45:41浏览:499

本文深入解析JavaScript中Promise对象的六个关键特性:链式调用产生的Forked Promise、回调返回值传递机制、异常捕获的范围限制、错误恢复导致的Promise状态反转、通过返回新Promise实现暂停与等待,以及Resolved状态异步执行的规范。掌握这些特性有助于编写更健壮、可维护的异步代码,避免常见的陷阱。

JavaScript Promise的基本形态

在正式探讨之前,我们先直观地看一下JavaScript中Promise的基本形态。

代码如下:

var p = new Promise(function(resolve, reject) {
resolve("hello world");
});
p.then(function(str) {
alert(str);
});

then()返回Forked Promise

1. then()返回一个Forked Promise

以下两段代码有什么区别呢?

代码如下:

// Exhibit A
var p = new Promise(/*...*/);
p.then(func1);
p.then(func2);
// Exhibit B
var p = new Promise(/*...*/);
p.then(func1)
.then(func2);

如果你认为以上两段代码等同,那么Promises仅仅是一个一维的回调函数数组。然而,事实并非如此。每一次调用then()都会返回一个Forked Promise(分叉的Promise)。因此,在Exhibit A中,如果func1()抛出异常,func2()仍会正常调用。

在Exhibit B中,如果func1()抛出错误,func2()将不会被调用。这是因为第一次调用返回了一个新的Promise,该Promise在func1()中处于拒绝状态,从而导致func2()被跳过。

总结:Promises可以被分叉成多条路径,类似于复杂的流程图。

回调函数应传递结果

2. Callback应该传递结果

当你运行下面代码时,会得到什么警告提示呢?

代码如下:

var p = new Promise(function(resolve, reject) {
resolve("hello world");
});
p.then(function(str) {})
.then(function(str) {
alert(str);
});

第二个then()中的alert没有显示任何内容。这是因为在Promise的上下文中,如果回调函数没有返回值,结果就不会传递给下一个回调。Promise期望你的回调函数返回相同的结果或者返回一个替换结果,然后将其传递到下一个回调函数中。

类似使用适配器来变化结果,如下:

代码如下:

var feetToMetres = function(ft) { return ft*12*0.0254 };
var p = new Promise(/*...*/);
p.then(feetToMetres)
.then(function(metres) {
alert(metres);
}); 

异常捕获的范围限制

3. 只有来自上一层的异常可以被捕捉

这两段代码有什么区别?

代码如下:

// Exhibit A
new Promise(function(resolve, reject) {
resolve("hello world");
})
.then(
function(str) {
throw new Error("uh oh");
  },
undefined
)
.then(
undefined,
function(error) {
alert(error);
  }
);
// Exhibit B
new Promise(function(resolve, reject) {
 resolve("hello world");
})
.then(
 function(str) {
 throw new Error("uh oh");
 },
 function(error) {
 alert(error);
 }
);

在第一段代码中,第一个then()中抛出的异常会被第二个then()捕捉,从而触发“uh oh”警告。这遵循了只有前一个层次的异常会被捕捉的规则。

在第二段代码中,回调函数和错误回调函数处于同一层次,这意味着当异常在回调中抛出时,不会被捕捉。实际上,第二段代码的错误回调仅会在Promise处于拒绝状态或Promise本身出错时才会触发。

错误恢复机制

4. 错误可以被恢复

在错误回调函数中,如果你不重新抛出错误,Promise会假设你已经从错误中恢复,并将其状态反转回已解决(Resolved)。在下面的例子中,“i'm saved”将会被显示,这是因为第一个then()中的错误回调没有重新抛出异常。

代码如下:

var p = new Promise(function(resolve, reject) {
reject(new Error("pebkac"));
});
p.then(
undefined,
function(error) { }
)
.then(
function(str) {
alert("I am saved!");
  },
function(error) {
alert("Bad computer!");
  }
);

Promise可以被看作洋葱上的层次。每一个then()添加另外一个层次到洋葱上。每一个层次代表了一个被处理的活动。当层次结束,结果被认为已经修复并且为下一个层次做好了准备。

Promises的暂停与等待

5. Promises可以被暂停

因为你已经准备好在一个then()方法中执行,并不意味着你不能暂停并提前运行其他操作。为了暂停当前的Promise,或者让它等待另一个Promise完成,只需在then()中返回另一个Promise即可。

代码如下:

var p = new Promise(/*...*/);
p.then(function(str) {
if(!loggedIn) {
return new Promise(/*...*/);
  }
})
.then(function(str) {
alert("Done.");
})

在前面代码中,直到新的Promise解析后提示才会出现。这是一种在现有异步代码路径中引入更多依赖的便捷方式。例如,你可能发现用户session已经超时,并且希望在继续前面的代码路径前初始化第二个登录。

Resolved Promises的异步执行

6. Resolved Promises并不会立刻执行

运行下面代码会得到提示框么?

代码如下:

function runme() {
var i = 0;
new Promise(function(resolve) {
resolve();
  })
.then(function() {
i += 2;
  });
alert(i);
}

因为Promise被立刻解析,然后then()方法被立刻执行,所以你可能会认为会弹出提示2。但是Promise定义要求所有的调用都被强制异步。因此提示会在变量i被修改前生成。

作者最新文章