一、Promise是什么

在 JavaScript 中,Promise 是一种解决异步操作的形式。Promise 能够让咱们更加优雅地解决异步操作,而不须要应用回调函数嵌套。

● Promise 是一门新的技术(ES6 标准),是 JS 中进行异步编程的新解决方案(旧计划是单纯应用回调函数,容易造成回调天堂)

● 常见异步操作:①fs 文件操作 ②数据库操作 ③Ajax ④定时器

● 具体表白:

  1. 从语法上看:Promise是一个构造函数 (本人身上有all、reject、resolve这几个办法,原型上有then、catch等办法)
  2. 从性能上看:promise对象用来封装一个异步操作并能够获取其胜利/失败的后果值

二、创立 Promise

创立一个 Promise 非常简单,只须要应用 Promise 构造函数即可。Promise 构造函数承受一个函数作为参数,这个函数叫做执行器函数(executor function)。执行器函数有两个参数:resolvereject。当异步操作胜利时,调用 resolve,并传递后果值作为参数;当异步操作失败时,调用 reject,并传递谬误对象作为参数。

const promise = new Promise(function(resolve, reject) {  // ... some code  if (/* 异步操作胜利 */){    resolve(value);  } else {    reject(reason);  }});

三、应用 Promise

应用 Promise 有两种形式:then 办法和 catch 办法。

1.then 办法

then 办法用于注册 Promise 胜利时的回调函数。当 Promise 胜利时,then 办法会被调用,并传递 Promise 胜利时的后果值作为参数。

promise.then((result) => {  // 解决 Promise 胜利时的后果值});

2.catch 办法

catch 办法用于注册 Promise 失败时的回调函数。当 Promise 失败时,catch 办法会被调用,并传递 Promise 失败时的谬误对象作为参数。

promise.catch((error) => {  // 解决 Promise 失败时的谬误对象});

四、Promise.resolve和Promise.reject

1.Promise.resolve 办法

在 JavaScript 中,Promise.resolve 是一个办法,它返回一个 Promise 对象,该对象以给定的值解析。如果该值自身是一个 Promise,则返回该 Promise;否则,返回一个以该值解析的新 Promise 对象。它通常用于将非 Promise 值转换为 Promise 对象,以便在 then 办法中应用。

Promise.resolve(value):

value:将被 Promise 对象解析的参数,也能够是一个胜利或失败的 Promise 对象

返回一个带着给定值解析过的 Promise 对象,如果参数自身就是一个 Promise 对象,则间接返回这个 Promise 对象

  • 1.如果传入的参数为 非Promise类型的对象, 则返回的后果为胜利promise对象
let p1 = Promise.resolve(521);console.log(p1); // Promise {<fulfilled>: 521}
  • 2.如果传入的参数为 Promise 对象, 则参数的后果决定了 resolve 的后果
let p2 = Promise.resolve(new Promise((resolve, reject) => {// resolve('OK'); // 胜利的Promisereject('Error');}));console.log(p2);p2.catch(reason => {console.log(reason);})

2.Promise.reject 办法

Promise.reject(reason):

reason:失败的起因

阐明:返回一个失败的 promise 对象

let p = Promise.reject(521);let p2 = Promise.reject('iloveyou');let p3 = Promise.reject(new Promise((resolve, reject) => {resolve('OK');}));console.log(p);console.log(p2);console.log(p3);   //reject 返回的promise调用的是resolve

● Promise.resolve()/Promise.reject() 办法就是一个语法糖,用来疾速失去Promise对象

五、Promise 的状态和状态转换

Promise 有三种状态:

pending(进行中)、fulfilled(已胜利)和 rejected(已失败)。Promise 的状态只能从 pending 转换为 fulfilledrejected,一旦状态转换实现,就不能再次转换。

上面是一个简略的例子,展现了 Promise 的状态和状态转换。

const promise = new Promise((resolve, reject) => {  setTimeout(() => {    resolve('result');  }, 1000);});console.log(promise); // Promise { <pending> }promise.then((result) => {  console.log(result); // result  console.log(promise); // Promise { <fulfilled>:'result' }});console.log(promise); // Promise { <pending> }

在下面的例子中,Promise 的初始状态为 pending,因为异步操作须要 1 秒钟能力实现。当异步操作实现并胜利时,Promise 状态转换为 fulfilled。在 then 办法中,咱们能够拜访 Promise 的后果值。最初,咱们再次打印 Promise 对象,能够看到它的状态曾经变为 fulfilled

如果异步操作失败,咱们能够调用 reject 办法,将 Promise 状态转换为 rejected

const promise = new Promise((resolve, reject) => {  setTimeout(() => {    reject(new Error('error'));  }, 1000);});promise.catch((error) => {  console.log(error); // Error: error    console.log(promise); // Promise { <rejected>: Error: error }});

在下面的例子中,异步操作失败,并且 Promise 状态转换为 rejected。在 catch 办法中,咱们能够拜访 Promise 的谬误对象。

六、Promise的几个关键问题

a、如何扭转 promise 的状态?

1.resolve(value):如果以后是 pending 就会变为 resolved

2.reject(reason):如果以后是 pending 就会变为 rejected

3.抛出异样:如果以后是 pending 就会变为 rejected

b、一个 promise 指定多个胜利/失败回调函数,都会调用吗?

当 promise 扭转为对应状态时都会调用

const p = new Promise((resolve, reject) => {//resolve(1)reject(2)})p.then(value => {},reason => {console.log('reason',reason)})p.then(value => {},reason => {console.log('reason2',reason)})// reason 2// reason2 2

c、promise.then() 返回的新 promise 的后果状态由什么决定?

(1)简略表白:由 then() 指定的回调函数执行的后果决定

(2)具体表白:

① 如果抛出异样,新 promise 变为 rejected,reason 为抛出的异样

② 如果返回的是非 promise 的任意值,新 promise 变为 resolved,value 为返回的值

③ 如果返回的是另一个新 promise,此 promise 的后果就会成为新 promise 的后果

d、promise 如何串联多个操作工作?

(1)promise 的 then() 返回一个新的 promise,能够并成 then() 的链式调用(2)通过 then 的链式调用串联多个同步/异步工作new Promise((resolve, reject) => {setTimeout(() => {console.log('执行工作1(异步)')resolve(1)}, 1000)}).then(value => {console.log('工作1的后果', value)console.log('执行工作2(同步)')return 2 // 同步工作间接return返回后果}).then(value => {console.log('工作2的后果', value)return new Promise((resolve, reject) => { // 异步工作须要包裹在Promise对象中setTimeout(() => {console.log('执行工作3(异步)')resolve(3)}, 1000)})}).then(value => {console.log('工作3的后果', value)})// 执行工作1(异步)// 工作1的后果 1// 执行工作2(同步)// 工作2的后果 2// 执行工作3(异步)// 工作3的后果 3

e、Promise 异样穿透(传透)?

(1)当应用 promise 的 then 链式调用时,能够在最初指定失败的回调

(2)后面任何操作出了异样,都会传到最初失败的回调中解决

new Promise((resolve, reject) => {//resolve(1)reject(1)}).then(value => {console.log('onResolved1()', value)return 2}).then(value => {console.log('onResolved2()', value)return 3}).then(value => {console.log('onResolved3()', value)}).catch(reason => {console.log('onRejected1()', reason)})// onRejected1() 1

失败的后果是一层一层解决下来的,最初传递到 catch 中

七、Promise.all 和 Promise.race

除了根底的 Promise,ES6 还提供了两个静态方法:Promise.allPromise.race。这两个办法能够让咱们更加不便地解决多个 Promise 实例。

1.Promise.all

Promise.all 办法用于将多个 Promise 实例包装成一个新的 Promise 实例。当所有 Promise 实例都胜利时,新的 Promise 实例才会胜利;当任意一个 Promise 实例失败时,新的 Promise 实例就会失败。

const promise1 = Promise.resolve(1);const promise2 = Promise.resolve(2);Promise.all([promise1, promise2]).then((results) => {  console.log(results); // [1, 2]});

在下面的例子中,Promise.all 办法承受一个 Promise 实例数组作为参数,返回一个新的 Promise 实例。当所有 Promise 实例都胜利时,新的 Promise 实例会胜利,并传递所有 Promise 实例的后果值数组作为参数。

2.Promise.race

Promise.race 办法用于将多个 Promise 实例包装成一个新的 Promise 实例。当其中申请最快的那个 Promise 实例胜利或失败时,新的 Promise 实例就会胜利或失败。

const promise1 = new Promise((resolve) => {  setTimeout(() => {    resolve(1);  }, 1000);});const promise2 = new Promise((resolve) => {  setTimeout(() => {    resolve(2);  }, 2000);});Promise.race([promise1, promise2]).then((result) => {  console.log(result); // 1});

在下面的例子中,Promise.race 办法承受一个 Promise 实例数组作为参数,返回一个新的 Promise 实例。当其中申请最快一个 Promise 实例胜利或失败时,新的 Promise 实例就会胜利或失败,并传递第一个胜利或失败的 Promise 实例的后果值或谬误对象作为参数。

艰深的讲,就是说你可能传给我了好几个异步,我都会去申请,然而只有有一个率先实现申请我就把他的后果(胜利/失败)返回给你。至于剩下的申请,我只帮你申请,他是对是错我就不论了,我只关注最快的那个。

八、Promise利用场景

1.防止回调天堂

Promise 能够让咱们更加优雅地解决异步操作,防止回调天堂。在应用 Promise 时,咱们应该尽量避免应用回调函数嵌套,而是应用 Promise 链式调用的形式。

asyncFunc1()  .then((result1) => {    return asyncFunc2(result1);  })  .then((result2) => {    return asyncFunc3(result2);  })  .then((result3) => {    console.log(result3);  })  .catch((error) => {    console.log(error);  });

2.处理错误

在应用 Promise 时,咱们应该尽可能地处理错误。应用 catch 办法能够解决 Promise 的谬误,避免出现未解决的谬误。

asyncFunc()  .then((result) => {    console.log(result);  })  .catch((error) => {    console.log(error);  });

3.返回 Promise

在编写函数时,如果函数外部有异步操作,咱们应该返回一个 Promise 实例,以便内部代码能够应用 Promise 的形式解决异步操作。

function asyncFunc() {  return new Promise((resolve, reject) => {    // 异步操作    // 胜利时调用 resolve(result)    // 失败时调用 reject(error)  });}

九、手写 Promise 实现原理

class MyPromise {  constructor(executor) {    this.state = 'pending';    this.value = undefined;    this.reason = undefined;    this.onResolvedCallbacks = [];    this.onRejectedCallbacks = [];    const resolve = (value) => {      if (this.state === 'pending') {        this.state = 'fulfilled';        this.value = value;        this.onResolvedCallbacks.forEach((fn) => fn());      }    };    const reject = (reason) => {      if (this.state === 'pending') {        this.state = 'rejected';        this.reason = reason;        this.onRejectedCallbacks.forEach((fn) => fn());      }    };    try {      executor(resolve, reject);    } catch (error) {      reject(error);    }  }  then(onFulfilled, onRejected) {    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value;    onRejected = typeof onRejected === 'function' ? onRejected : (reason) => { throw reason; };    const promise2 = new MyPromise((resolve, reject) => {      if (this.state === 'fulfilled') {        setTimeout(() => {          try {            const x = onFulfilled(this.value);            this.resolvePromise(promise2, x, resolve, reject);          } catch (error) {            reject(error);          }        });      }      if (this.state === 'rejected') {        setTimeout(() => {          try {            const x = onRejected(this.reason);            this.resolvePromise(promise2, x, resolve, reject);          } catch (error) {            reject(error);          }        });      }      if (this.state === 'pending') {        this.onResolvedCallbacks.push(() => {          setTimeout(() => {            try {              const x = onFulfilled(this.value);              this.resolvePromise(promise2, x, resolve, reject);            } catch (error) {              reject(error);            }          });        });        this.onRejectedCallbacks.push(() => {          setTimeout(() => {            try {              const x = onRejected(this.reason);              this.resolvePromise(promise2, x, resolve, reject);            } catch (error) {              reject(error);            }          });        });      }    });    return promise2;  }  resolvePromise(promise2, x, resolve, reject) {    if (promise2 === x) {      return reject(new TypeError('Chaining cycle detected'));    }    let called = false;    if (x !== null && (typeof x === 'object' || typeof x === 'function')) {      try {        const then = x.then;        if (typeof then === 'function') {          then.call(x, (y) => {            if (called) return;            called = true;            this.resolvePromise(promise2, y, resolve, reject);          }, (r) => {            if (called) return;            called = true;            reject(r);          });        } else {          resolve(x);        }      } catch (error) {        if (called) return;        called = true;        reject(error);      }    } else {      resolve(x);    }  }  catch(onRejected) {    return this.then(null, onRejected);  }  static resolve(value) {    return new MyPromise((resolve) => {      resolve(value);    });  }  static reject(reason) {    return new MyPromise((_, reject) => {      reject(reason);    });  }  static all(promises) {    return new MyPromise((resolve, reject) => {      const results = [];      let count = 0;      for (let i = 0; i < promises.length; i++) {        promises[i].then((result) => {          results[i] = result;          count++;          if (count === promises.length) {            resolve(results);          }        }, reject);      }    });  }  static race(promises) {    return new MyPromise((resolve, reject) => {      for (let i = 0; i < promises.length; i++) {        promises[i].then(resolve, reject);      }    });  }}

在下面的代码中,咱们创立了一个 MyPromise 类,它蕴含了 Promise 的根本实现。咱们实现了 Promise 的基本功能,包含状态的扭转、then 办法和 catch 办法的实现、Promise 的链式调用、错误处理和静态方法 resolverejectallrace 的实现。

十、总结

Promise 是一种解决异步操作的形式,它能够让咱们更加优雅地解决异步操作。在应用 Promise 时,咱们应该遵循一些最佳实际,包含防止回调天堂、处理错误和返回 Promise。心愿这篇文章可能帮忙你更好地应用 Promise。