你好,promise

276 阅读4分钟

像结识了一位新朋友一样,最近开始学习了promise。一开始接触到这个名词的时候也在脑海中想,promise是到底是做什么的呢。那么下面跟我一起来认识一下promise把。

首先来了解一下promise的含义

简单来说,promise是一种异步流程的控制手段,比传统的回调函数解决方案更合理和简洁。它解决了传统回调函数方式产生的回调地狱的问题。ES6将其写进了语言标准,统一了语法,原生提供了Promise。

下面我们来看一个简单的例子:

有这么一个场景,想做一道菜:首先要去买菜,买完菜之后才能洗菜,洗完菜之后才能切菜,切完之后才能炒菜,转换成js如下:

function A(callback){
    setTimeout(function(){
        callback("菜买好了");
    }, 1000);
}
function B(callback){
     setTimeout(function(){
          callback("菜洗好了");
     }, 2000);
}
function C(callback){
     setTimeout(function(){
          callback("菜切好了");
     }, 3000);
} 
function D(callback){
     setTimeout(function(){
          callback("菜炒好了");
     }, 3000);
} 
  • 传统的回调函数方式是
A(function(res){
     console.log(res);
     B(function(res){
          console.log(res);
          C(function(res){
                console.log(res);
                C(function(res){
                    console.log(res);
                    console.log("菜炒好啦");
                }); 
          });
     });
});

这就是传说中的回调地狱,实际的场景嵌套的层级可能还更多。这种代码非常不易于理解,而且代码难以维护。 而promise就非常适合这种场景,上面的代码用promise实现

function A() {
    return new Promise(function (resolve, reject) {
         setTimeout(function(){
            resolve("菜买好了");
        }, 1000);
    });
}
function B() {
    return new Promise(function (resolve, reject) {
          setTimeout(function(){
               resolve("菜洗好了");
          }, 2000);
    });
}
function C() {
    return new Promise(function (resolve, reject) {
          setTimeout(function(){
               resolve("菜切好了");
          }, 2000);
    });
}
function D() {
    return new Promise(function (resolve, reject) {
          setTimeout(function(){
               resolve("菜炒好了");
          }, 2000);
    });
}

A().then(function(res) {
    console.log(res);
    return B();
}).then(function(res) {
    console.log(res);
    return C();
}).then(function(res) {
    console.log(res);
    return D();
}).then(function(res) {
    console.log(res);
    console.log("菜炒好了");
});

可见Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了。

深入理解promise

Promise对象可以理解为一次将要执行的操作(常常被用于异步操作),使用了 Promise 对象之后可以用一种链式调用的方式来组织代码,让代码更加直观。promise 实现链式调用返回的并不是this而是一个新的promise。

promise(承诺)有三种状态,分别是

  • resolve (成功)
  • reject (失败)
  • pending (等待态)

状态改变: Promise对象的状态改变,只有两种可能: 从pending变为reject。 从pending变为resolve 如果一旦promise成功了就不能失败,相反也是一样的。所以这两种情况只要发生,状态就凝固了,不会再变了,这时就称为resolved(已定型)。

每一个promise的实例上都有一个then方法,then方法中有两个参数,一个参数叫成功的函数 ,一个是失败的函数。 then方法定义:then(fulfilledAHandler, errorHandler),对应着Promise的resolve, reject。

一个promise可以then多次

let p = new Promise((resolve,reject)=>{
  resolve('成功');
});
p.then(data=>{
  console.log(data);
});
p.then(data=>{
  console.log(data);
})
p.then(data => {
  console.log(data);
});

promise中只要发生错误,就会执行失败态。如果返回的是一个普通值就会走到写一个then中的成功回调,如果有错误产生会走失败的回调。

  • Promise只有一个参数 叫excutor执行器,默认new时就会调用
let p = new Promise((resolve,reject)=>{ 
  // 默认promise中的executor是同步执行的
   resolve('买');
});
// then方法是异步调用的,事件环
p.then(
(value)=>{ // value成功
  console.log(1);
},
(err)=>{ // err失败
});
console.log(2);

执行结果,2 1。

promise可以处理并发任务

promise用promise.all方法做并发调用,当所有Promise 对象都变为完成态或失败态时,回调将被执行。

let fs = require('fs'); // fileSystem
function read(url) {
  return new Promise((resolve, reject) => {
    fs.readFile(url, 'utf8', function (err, data) {
      if (err) reject(err);
      resolve(data);
    })
  })
}

Promise.all([read('1.txt'),read('2.txt')]).then((data)=>{
   console.log(data);
 },err=>{
   console.log(err);
 });

promise.race赛跑,处理多请求只取最快的

Promise.all([read('1.txt'),read('2.txt')]).then((data)=>{
   console.log(data);
 },err=>{
   console.log(err);
 });

读取哪个文件快,返回哪个文件的结果

Promise.resolve() 返回一个成功的promise

Promise.reject() 返回一个失败的promise

promise.reject('123').then(null,data=>{
  console.log(data);
});

最后用es6语法简单实现一下Promise的原理

class Promise {
  constructor(executor) {
    this.status = 'pending';
    this.value = undefined;
    this.reason = undefined;
    let resolve = value => {
      if (this.status ==='pending'){
        this.status = 'resolved';
        this.value = value;
      }
    }
    let reject = reason => {
      if (this.status === 'pending') {
        this.status = 'rejected';
        this.reason = reason;
      }
    }
    try {
      executor(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }
  then(onFufilled,onRjected){
    if(this.status === 'resolved'){
      onFufilled(this.value);
    }
    if(this.status === 'rejected'){
      onRjected(this.reason);
    }
  }
}
module.exports = Promise