ES6之promise

Promise对象用于表示一个异步操作的最终状态(完成或失败)以及其返回的值。---MDN

同步任务会阻塞程序执行(alert、for、...)。

异步任务不会阻塞程序执行(setTimeout、fs.readFile、....)。

promise对象放的是我们未来要做的事情,当我们实例化这个对象后,就开始做这个事。成功做成功的事,失败做失败的事。之前解决异步主要方式是通过回调函数,事件。

使用Promise(then、catch、finally)

Promise.all & Promise.race

Promise.resolve & Promise.reject

// 比较传统的回调方式与promise

// -------------------------------------------------------
// 回调

// 方法 用于请求数据(模拟)
// function f(cb) {
//     setTimeout(function() {
//         cb && cb();//短路操作,与,前面的对了,执行后面的操作。
//     }, 1000);
// }

// f(function() {
//     console.log(1);

//     f(function() {
//         console.log(2);

//         f(function() {
//             console.log(3);

//             f(function() {
//                 console.log(4);

//                 f(function() {
//                     console.log(5);

//                     f(function() {
//                         console.log(6);
//                     });
//                 });
//             });
//         });
//     });
// });

// -------------------------------------------------------
// promise

// 方法 用于请求数据(模拟)
function f() {
    return new Promise(resolve => {
        setTimeout(function() {
            resolve();
        }, 1000);
    })
}

f()
    .then(function() {
        console.log(1);
        return f();//注意这里返回的是新的promise对象,而不是第一个生成的。
    })
    .then(function() {
        console.log(2);
        return f();
    })
    .then(function() {
        console.log(4);
        return f();
    })
    .then(function() {
        console.log(3);
        return f();
    })
    .then(function() {
        console.log(5);
        return f();
    })
    .then(function() {
        console.log(6);
    });

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

// 信任问题

// 第三方的某个库
function method(cb) {
  // 未按所想的预期执行回调
  setTimeout(function() {
    // 讲道理应该是现在该调用回调了
    cb && cb();
    // 但是?? 好像这个库有bug啊 emm 被多调用了一次
    cb && cb();
  }, 1000);
}

// promise一但被确定为成功或者失败 就不能再被更改

function method() {
  return new Promise(resolve => {
    setTimeout(function() {
      // 成功
      resolve();
      resolve();
    }, 1000);
  });
}


// 控制反转

function method(cb) {
  // 未按所想的预期执行回调
  setTimeout(function() {
    // 执行回调 但是添油加醋
    cb && cb.call({a: 1, b: 2});
  }, 1000);
}

function method(cb) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(); // 调用的resolve全为自己所写书写的流程 很大程度上改善了反转控制的问题
    }, 1000);
  });
}

错误处理:

function f(val) {
  return new Promise((resolve, reject) => {
    if (val) {
      resolve({ name: '小明' });//只能传递一个参数,第二个取不到。
    } else {
      reject('404');
    }
  }); 
}

// then(resolve, reject)
// then方法中的第二个回调 失败时候做的事

// f(false)
//   .then((data) => {
//     console.log(data)
//   }, e => {
//     console.log(e);
//   })

//----------------------------------------
// catch
// 使用实例的catch方法 可以捕获错误

// f(true)
//   .then(data => {
//     console.log(data);
//     return f(false);
//   })
//   .then(() => {//若是错误没有被处理,则中间的代码都不会执行,除非有对错误进行处理。
//     console.log('我永远不会被输出');
//   })
//   .then(() => {

//   })
//   .catch(e => {
//     console.log(e);
//     return f(false) ;
//   });

//----------------------------------------
// finally
// 不论成功还是失败 finally中的内容一定会执行

f(true)
  .then(data => {
    console.log(data);
    return f(false);
  })
  .catch(e => {
    console.log(e);
    return f(false);
  })
  .finally(() => {
    console.log(100);
  });

注意:Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject,它们是两个函数then方法可以接受两个回调函数作为参数,第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用,其中,第二个函数是可选的,不一定要提供,Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。

 

Pormise有三种状态:pending进行中,fulfilled成功,rejected失败。状态的改变只有两种,

从pending--》fulfilled,从pending--》rejected。状态的改变不可逆,一旦决议不能再修改。

 

(1)对象的状态不受外界影响,Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败),只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态,这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果,Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected,只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型),如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果,这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

 

// Promise.all方法可以把多个promise实例 包装成一个新的promise实例
// Promise.all([ promise1, promise2 ]) : Promise//接收一个数组,数组中的值为promise对象
//若是存在失败的promise,则判断为失败,全部成功才为成功。
//默认会将参数用promise.resolve()包一下。
// 模拟需要多个请求的数据 才能进行下一步操作的情况 // function getData1() { // return new Promise((resolve, reject) => { // setTimeout(() => { // console.log('第一条数据加载成功'); // resolve('data1'); // }, 1000); // }); // } // function getData2() { // return new Promise((resolve, reject) => { // setTimeout(() => { // console.log('第二条数据加载成功'); // resolve('data2'); // }, 1000); // }); // } // function getData3() { // return new Promise((resolve, reject) => { // setTimeout(() => { // console.log('第三条数据加载成功'); // resolve('data3'); // }, 1000); // }); // } // function getData4() { // return new Promise((resolve, reject) => { // setTimeout(() => { // // console.log('第四条数据加载成功'); // reject('data4 err'); // }, 500); // }); // } // let p = Promise.all([]);//传入空数组,决议会成功 // p.then(() => { // console.log('dfsafd'); // }, e => { // console.log(e); // }); // 不是用Promise.all // let count = 0; // let err = false; // function func() { // if (count < 4) return; // if (err) { // // .... // } // console.log('全部拿到了 !'); // } // function getData1() { // setTimeout(() => { // console.log('第一条数据加载成功'); // count ++; // func(); // }, 1000); // } // function getData2() { // setTimeout(() => { // console.log('第二条数据加载成功'); // count ++; // func(); // }, 1000); // } // function getData3() { // setTimeout(() => { // console.log('第三条数据加载成功'); // count ++; // func(); // }, 1000); // } // function getData4() { // setTimeout(() => { // console.log('第四条数据加载成功'); // count ++; // func(); // }, 1000); // } // getData1(); // getData2(); // getData3(); // getData4();

 promise.race();//和all不同的地方在于,一旦有一个promise实例成功或者失败了,那该方法马上返回promise实例就为成功或者失败。传入空数组时,什么反应都没有。其他与promise.all()方法相同。

// Promise.resolve() 和 Promise.reject()
// 常用来生成已经被决议为失败或者成功的promise实例

// Promise.resolve
// ---------------------------------------
// 传递一个普通的值
// let p1 = new Promise(resolve => {
//   resolve('成功!');
// });

// let p2 = Promise.resolve('成功!');
//以上两种方法等价。返回的是promise实例对象。
// // ---------------------------------------
// // 传递一个promise实例
// let poruomiesi = new Promise(resolve => {
//   resolve('耶!')
// });

// // 直接返回传递进去的promise
// let p = Promise.resolve(poruomiesi);

// p.then(data => void console.log(data));

// console.log(p === poruomiesi); //true

// // ---------------------------------------
// // 传递一个thenable
// // 如果传递的是个thenable,则会把他包装成promise对象并立即执行该对象的then方法。//概念和类数组和数组的关系有点类似,鸭子类型。
// let obj = {
//   then(cb) {
//     console.log('我被执行了');
//     cb('哼!');
//   },
//   oth() {
//     console.log('我被抛弃了');
//   }
// }

// // 立即执行then方法
// Promise.resolve(obj).then(data => {
//   console.log(data);
// });

// // Promise.reject 

// Promise.reject({ then() { console.log(1) } })
//   .then(() => {
//     console.log('我不会被执行');
//   }, e => {
//     console.log(e);
//   });

// console.log(1);

// let p = new Promise(resolve => {
//   console.log(2);
//   resolve();
//   console.log(3);
// });

// console.log(4);

// p.then(() => {
//   console.log(5);
// });

// console.log(6);


// 把同步的任务转成异步任务

function createAsyncTask(syncTask) {//自己封装的一个将同步任务转化成异步任务的函数
  return Promise.resolve(syncTask).then(syncTask => syncTask());
}

createAsyncTask(() => {
  console.log('我变成了异步任务!!!');
  return 1 + 1;
}).then(res => {
  console.log(res);
});

console.log('我是同步任务!');

 小案例:

// 页面中有个板块 需要多张图片加载完之后才能进行展示

const loadImg = src => {
    return new Promise((resolve, reject) => {
        const img = new Image();

        img.src = src;

        img.onload = void resolve(img);
        img.onerror = void reject('加载失败');
    });
};

const imgs = [
    'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1526734981&di=fe12efe9e3a76bd3bb5ac202a3c76823&imgtype=jpg&er=1&src=http%3A%2F%2Fd15.lxyes.com%2F15xm%2Fact%2F20151105%2F20%2F99112408.jpg',
    'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1252816855,3131381110&fm=27&gp=0.jpg',
    'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1906477750,651116720&fm=27&gp=0.jpg'
];

Promise.all(imgs.map(src => loadImg(src))).then(arr => {
    console.log(arr);
});

 

posted @ 2018-12-22 11:20  骨子里的钟  阅读(171)  评论(0编辑  收藏  举报