是什么?

promise 是一个对象,它可能会在未来的某个时间产生一个值。并且你可以声明

  1. 未来获取到值时应该怎么做
  2. 如果出现异常怎么做
  3. 不论结果如何都要干的事情

    怎么来的?

    回调是怎么回事儿?

    article on callbacks
    错误使用

    const getData = function() {
    // go fetch data from some API...
    // clean it up a bit and return it as an object:
    return data
    }
    const myData = getData()
    // 需要注意由于请求数据是异步操作,所以并不会等待获取到数据了,才执行下面这句话。
    // 最终结果即使 myData 是undefine
    const pieceOfData = myData['whatever']

    正确使用

    const myData = getData() // if this is refactored to return a Promise...
    // 通过Fetch会返回一个Promise对象,我们告诉它当正确读取到数据时,应该怎么做
    myData.then(function(data){ // .then() tells it to wait until the promise is resolved
    const pieceOfData = data['whatever'] // and THEN run the function inside
    })

    怎么用?

    基础用法

    var p = new Promise(function(resolve, reject) {
    // Do an async task async task and then...
    if(/* good condition */) {
    resolve('Success!');
    }
    else {
    reject('Failure!');
    }
    });
    p.then(function(result) {
    /* do something with the result */
    }).catch(function() {
    /* error :( */
    }).finally(function() {
    /* executes regardless or success for failure */
    });

    将原先的XMLHttpRequest优化为使用Promise

    function get(url) {
    return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.onload = () => {
    if (xhr.status === 200) {
    resolve(xhr.response);
    } else {
    reject(xhr.statusText);
    }
    };
    xhr.send();
    });
    }
    // 写法一
    get('story.json').then(function(response) {
    console.log("Success!", response);
    }, function(error) {
    console.error("Failed!", error);
    });
    // 写法二: 更直观一点
    get('story.json').then((response) => {
    console.log("Success!", response);
    }).catch((error) => {
    console.error("Failed!", error);
    })

    使用类方法

    var userCache = {};
    function getUserDetail(username) {
    // In both cases, cached or not, a promise will be returned
    if (userCache[username]) {
    // Return a promise without the "new" keyword
    return Promise.resolve(userCache[username]);
    }
    // Use the fetch API to get the information
    // fetch returns a promise
    return fetch('users/' + username + '.json')
    .then(function(result) {
    userCache[username] = result;
    return result;
    })
    .catch(function() {
    throw new Error('Could not find user: ' + username);
    });
    }

    Promise.all

    当执行多个异步操作,希望所有异步操作都执行完了,再触发回调
    Promise.all([promise1, promise2]).then(function(results) {
    // Both promises resolved
    })
    .catch(function(error) {
    // One or more promises was rejected
    });
    具体做法
    var request1 = fetch('/users.json');
    var request2 = fetch('/articles.json');
    Promise.all([request1, request2]).then(function(results) {
    // Both promises done!
    })
    当然如果有任意一个异步操作失败,都会直接触发rejection,并且catch到第一个rejection的Promise
    var req1 = new Promise(function(resolve, reject) {
    // A mock async action using setTimeout
    setTimeout(function() { resolve('First!'); }, 4000);
    });
    var req2 = new Promise(function(resolve, reject) {
    // A mock async action using setTimeout
    setTimeout(function() { reject('Second!'); }, 3000);
    });
    Promise.all([req1, req2]).then(function(results) {
    console.log('Then: ', results);
    }).catch(function(err) {
    console.log('Catch: ', err);
    });

    Promise.race

    该操作也是执行多个Promise,不同的是只要有一个Promise成功或失败,都会立刻触发
    var req1 = new Promise(function(resolve, reject) {
    // A mock async action using setTimeout
    setTimeout(function() { resolve('First!'); }, 8000);
    });
    var req2 = new Promise(function(resolve, reject) {
    // A mock async action using setTimeout
    setTimeout(function() { resolve('Second!'); }, 3000);
    });
    Promise.race([req1, req2]).then(function(one) {
    console.log('Then: ', one);
    }).catch(function(one, two) {
    console.log('Catch: ', one);
    });

实践说明

通过一个小的需求,通过不断的优化,回调->promise->sync/await

需求说明:

我们希望红绿灯能循环执行,比如红灯执行三秒后,执行绿灯,绿灯执行两秒后执行黄灯,黄灯执行一秒后再执行红灯。

基础函数:

function red() {
  console.log("red...");
}

function green() {
  console.log("green...");
}

function yello() {
  console.log("yello...");
}

使用回调

const task = (time, color, callback) => {
  setTimeout(() => {
    if (color == "red") {
      red();
    }
    if (color == "green") {
      green();
    }
    if (color == "yello") {
      yello();
    }
    callback();
  }, time);
};

const step = () => {
  task(1000, "red", () => {
    task(3000, "green", () => {
      task(2000, "yello", step);
    });
  });
};

step();

可以看到有很多的嵌套

执行Promise

const task = (time, color) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (color == "red") {
        red();
      }
      if (color == "green") {
        green();
      }
      if (color == "yello") {
        yello();
      }
      resolve();
    }, time);
  });
};

const step = () => {
  task(1000, "red")
    .then(() => task(3000, "green"))
    .then(() => task(2000, "yello"))
    .then(() => step());
};

step();

通过一个个then保证依次顺序执行,代码简单化

使用sync/await

const task = (time, color) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (color == "red") {
        red();
      }
      if (color == "green") {
        green();
      }
      if (color == "yello") {
        yello();
      }
      resolve();
    }, time);
  });
};

const step = async () => {
  await task(1000, "red");
  await task(3000, "green");
  await task(2000, "yello");
  step();
};
step();

通过sync/await 将代码进一步简化,通过函数调用的方式进行声明

解决现实问题

一个需求中,当用户执行某个操作时,会对操作数据状况进行校验,通过确认框进行用户提醒,当有多个情况需要确认时,会先进行第一个提示框提醒,点击确认后,再弹出第二个提示框进行确认。

最初实现方式

// 先服务再到款-确认订单状态
function check_order_status() {
  let that = this;

  this.$Modal.confirm({
    title: this.info("title", "title_bar.return_draft"),
    content: this.info("content", "title_bar.return_draft.associate_order"),
    onOk: () => setTimeout(() => that.check_payment_status(), 350),
  });
}
// 先服务再到款-确认到款状态
function check_payment_status() {
  let that = this;

  this.$Modal.confirm({
    title: this.info("title", "title_bar.return_draft"),
    content: this.info("content", "title_bar.return_draft.payment"),
    onOk: () => setTimeout(() => that.check_invoice_status(), 350),
  });
}
// 先服务再到款-确认开票状态
function check_invoice_status() {
  let that = this;

  this.$Modal.confirm({
    title: this.info("title", "title_bar.return_draft"),
    content: this.info("content", "title_bar.return_draft.invoice"),
    onOk: () => that.drawbackQuotation(),
  });
}

this.check_order_status();

可以看到函数之间耦合在一起,维护起来很麻烦,每个判断信息应该是独立的,通过外部去控制先后顺序

代码优化

// 先服务再到款-确认订单状态
function check_order_status() {
  let that = this;
  return new Promise((resolve, reject) => {
    this.$Modal.confirm({
      title: this.info("title", "title_bar.return_draft"),
      content: this.info("content", "title_bar.return_draft.associate_order"),
      onOk: () => resolve(),
    });
  });
}

// 先服务再到款-确认到款状态
function check_payment_status() {
  let that = this;
  return new Promise((resolve, reject) => {
    this.$Modal.confirm({
      title: this.info("title", "title_bar.return_draft"),
      content: this.info("content", "title_bar.return_draft.payment"),
      onOk: () => resolve(),
    });
  }
}

// 先服务再到款-确认开票状态
function check_invoice_status() {
  let that = this;
  return new Promise((resolve, reject) => {
    this.$Modal.confirm({
      title: this.info("title", "title_bar.return_draft"),
      content: this.info("content", "title_bar.return_draft.invoice"),
      onOk: () => resolve(),
    });
  }
}

const checkProccess = async () => {
  await check_order_status()
  await check_payment_status()
  await check_invoice_status()
}

可以看到代码一下优雅可维护了许多