Promise

Promise 对象用于表示一个异步操作的最终完成 (或失败),及其结果值。

本质上,Promise 是一个被某些函数传出的对象,我们附加回调函数(callback)使用它,而不是将回调函数传入那些函数内部。

  • Promise 状态

有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。

var promise1 = new Promise(function(resolve, reject) {
 setTimeout(resolve, 100, 'foo');
});

console.log(promise1);
// expected output: [object Promise]
  • 执行顺序
let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(function() {
  console.log('resolved.');
});

console.log('Hi!');

// Promise
// Hi!
// resolved

上面代码中,Promise 新建后立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。

注意,调用resolvereject并不会终结 Promise 的参数函数的执行。

new Promise((resolve, reject) => {
  resolve(1);
  console.log(2);
}).then(r => {
  console.log(r);
});
// 2
// 1

上面代码中,调用resolve(1)以后,后面的console.log(2)还是会执行,并且会首先打印出来。这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。

setTimeout(function () {
  console.log('three');
}, 0);

Promise.resolve().then(function () {
  console.log('two');
});

console.log('one');

// one
// two
// three

上面代码中,setTimeout(fn, 0)下一轮“事件循环”开始时执行,Promise.resolve()本轮“事件循环”结束时执行,console.log('one')则是立即执行,因此最先输出。

  • 错误捕获

Promise 内部的错误不会影响到 Promise 外部的代码。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

推荐写法,使用 catch;catch 之后,再接 then,可以继续执行。

promise
  .then(function(data) { //cb
    // success
  })
  .catch(function(err) {
    // error
  });

抛出错误可以用两种语法:

throw 'error message!';

return Promise.reject('error message!');
  • Promise.all 将多个 Promise 实例,包装成一个新的 Promise 实例

接受一个数组作为参数,p1p2p3都是 Promise 实例

Promise.all([p1, p2, p3])

如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()catch方法。该实例执行完catch方法后,也会变成resolved,导致Promise.all()方法参数里面的两个实例都会resolved,因此会调用then方法指定的回调函数。

Promise.all 等待所有都完成(或第一个失败)。

如果传入的 promise 中有一个失败(rejected),Promise.all 异步地将失败的那个结果给失败状态的回调函数,而不管其它 promise 是否完成。

var p1 = new Promise((resolve, reject) => { setTimeout(resolve, 1000, 'one'); }); 
var p2 = new Promise((resolve, reject) => { setTimeout(resolve, 2000, 'two'); }); 
var p3 = new Promise((resolve, reject) => { reject('reject'); });
Promise.all([p1, p2, p3).then(values => { 
  console.log(values);
}, reason => {
  console.log(reason)
});

//控制台打印:
//"reject"
//你也可以用 .catch
Promise.all([p1, p2, p3]).then(values => { 
  console.log(values);
}).catch(reason => { 
  console.log(reason)
});

//控制台打印: 
//"reject"
  • 加载图片
const preloadImage = function (path) {
  return new Promise(function (resolve, reject) {
    const image = new Image();
    image.onload  = resolve;
    image.onerror = reject;
    image.src = path;
  });
};
  • 传值方式

new Promise向下传值用 resolve,then 向下传值用 return。

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('foo');
  }, 300);
});
myPromise
  .then(value => { return value + ' and bar'; })
  .then(value => { return value + ' and bar again'; })
  .then(value => { return value + ' and again'; })
  .then(value => { console.log(value) })
  .catch(err => { console.log(err) });

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注