Promise-基础知识

前言

Promise 是异步编程的一种解决方案,用类似同步的代码写异步。以前接触过 setTimeout 或 ajax 回调地狱的童鞋应该深有体会。

可以把Promise 想象成一个封闭的状态机,根据异步操作的成功与否,调用不同的回调,并改变Promise对象的状态。异步操作成功时,调用resolve,失败时,调用reject。

优点

① 比 回调和事件 更强大,代码更易阅读。

② Promise 构造函数接收一个函数作为参数,该函数的两个参数分别是 reslove 和 reject。这两个参数,也是函数,由JavaScript 引擎提供。我们只需要传入这两个参数,然后调用它们,无需自己编写 resolve 或 reject 函数。

const p = new Promise((resolve, reject) => {
    resolve('ok');
})

缺点

① Promise 无法取消。new 一个 Promise 实例之后代码会立即执行,不能中途打断。

② Promise 内部抛出的错误 (throw 或 代码错误),如果用了 Promise 的 catch 去捕获,Promise 的 catch 可以捕获到,但是不会反应到外部,也就是控制台不会抛出错误。

扫描二维码关注公众号,回复: 938301 查看本文章

特性

① Promise对象 的 状态 一旦改变,就不会再变了。

② then 返回的是一个新的 Promise 实例。当 then 链式调用时,如果 then 里面返回的是 Promise 对象,那 后一个 then 就会等待前一个 then 里面的 Promise 状态改变后才会执行。

③ catch用于捕获 reject 状态, 或者 代码中抛出的错误。它返回的也是 Promise 对象,相当于是 then 的语法糖  — then( null, reject )。所以 catch 之后可以再接 then。

④ resolve 或 reject 代码段之后 的代码,依然会执行。而且会比 then 里面的代码先执行。

 为何会先执行? 是因为 事件循环机制, 事件循环机制主要有两个知识点: macroTask ( 主体代码 和 setTimeout 等 ) 和 microTask ( Promise 和 process.nextTick 等 )。具体内容参考 知乎用户何幻的回答  。我觉得讲得比较好。

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

⑤ fanally 的作用 可参考 try - catch- fanally 无论 是resolve,还是reject,都会执行。

运用

基础知识点介绍完了,接下来就看看怎么用吧

常见的用法:

 ① Promise 封装 ajax

const fetch = url => {
    const promise = new Promise((resolve, reject) => {
        const handler = function(){
            if (this.readyState !== 4) {
                return;
            }
            if (this.status === 200) {
                resolve(this.response);
            } else {
                reject(this.statusText);
            }
        }
        const xhr = new XMLHttpRequest();
        xhr.open('get', url);
        xhr.onreadystatechange = handler;
        xhr.send();
    });
    
    return promise;
}

② 加载图片

const getImage = url => {
    const promise = new Promise((resolve, reject) => {
        const img = new Image();
        img.onload = resolve;
        img.onerror = reject;
        img.src = url;
    });
    return promise;
}

③ promise 顺序执行。

有时候,我们会有多个请求,而请求之间会有依赖关系。比如下一个请求依赖上一个请求的数据。这个时候,我们就需要顺序执行了,可以封装个函数。( 当然,用 async/await  就更好了。)
这里我借用一下,上面的 fetch 函数 ( 不是官方的 fetch )。

const createQueue = (...args) => args;

const firstReq = () => fetch('https://azu.github.io/promises-book/json/comment.json').then(JSON.parse);
const secondReq = () => fetch('https://azu.github.io/promises-book/json/people.json').then(JSON.parse);

const reqQueue = createQueue(firstReq, secondReq);
const start = (queue = []) => {
    // 将两次请求到的数据,合并在一个数组
    const pushValue = (result => value => result = result.concat(value))([]);  
  // 相当于 Promise.resolve().then(firstReq).then(pushValue).then(secondReq).then(pushValue)
return queue.reduce((promise, req) => promise.then(req).then(pushValue), Promise.resolve()); } start(reqQueue).then(value => console.log(value));

静态方法

① Promise.resolve 将现有对象转为 Promise 对象,立即执行并返回一个 新的 promise 实例。等价于 new Promise( resolve => resolve() )。具体可以看 es6-promise

② Promise.reject 返回一个新的 Promise 实例,该实例的状态为rejected

③ Promise.race 将多个 Promise 实例,包装成一个新的 Promise 实例。只要一个 Promise 实例 resolve,就执行下一步。

④ Promise.all    将多个 Promise 实例,包装成一个新的 Promise 实例。需要所有 Promise 实例 resolve 或者 有一个 Promise 实例 reject,才执行下一步 。

⑤ Promise.try  暂未了解。

总结

① 任何异步的操作都可以用 Promise, 只需要在异步操作成功的时候,执行 resolve。

② catch 之后 是可以 再接 then。

参考

http://es6.ruanyifeng.com/#docs/promise

http://liubin.org/promises-book/#promise-sequence

猜你喜欢

转载自www.cnblogs.com/jkCaptain/p/9059982.html
今日推荐