手写promise---从promise到asycn/await

https://juejin.im/post/5b55c28ee51d45195a7139d6

/*Promise 的简单实现*/

class MyPromise {
    constructor(fn) {
        this.resolvedCallbacks = [];
        this.rejectedCallbacks = [];
        this.state = "PADDING";
        this.value = "";
        fn(this.resolve.bind(this), this.reject.bind(this));
    }
    resolve(value) {
        if (this.state === "PADDING") {
            this.state = "RESOLVED";
            this.value = value;
            this.resolvedCallbacks.forEach(cb => cb());
        }
    }
    reject(value) {
        if (this.state === "PADDING") {
            this.state = "REJECTED";
            this.value = value;
            this.rejectedCallbacks.forEach(cb => cb());
        }
    }
    then(resolve = function() {}, reject = function() {}) {
        if (this.state === "PADDING") {
            this.resolvedCallbacks.push(resolve);
            this.rejectedCallbacks.push(reject);
        }
        if (this.state === "RESOLVED") {
            resolve(this.value);
        }
        if (this.state === "REJECTED") {
            reject(this.value);
        }
    }
}

扩展 Promise.prototype.then和Promise.prototype.catch方法返回promise对象,所以它可以被链式调用。但此时返回的是以函数返回值生成的新的Promise实例,不是原来的那个Promise实例。
1.Promise对象的错误具有冒泡性质,会一直向后传递,直到被捕获为止。也就是说错误一定会被catch语句捕获。

,既然我then()方法第二个参数可以用来抛出错误,干嘛还要用这个catch()方法。
其实还是有区别的,在链式操作里,任何promise抛出的同步或异步错误都可以被then()方法捕获,而reject则处理当前promise的错误。因此,建议不要在then方法里面定义 reject 状态的回调函数(即then的第二个参数),总是使用catch方法,这样也更接近同步的写法(try/catch)。

使用.catch()捕捉错误
// ------------    不好的写法   -------------
promise.then(function(data) {
    // success
  }, function(err) {   //仅处理promise运行时发生的错误。无法处理回调中的错误
    // error
  });

// ------------    好的写法    ------------
promise.then(res => {
    // success
}).catch(err => {   // 处理 promise 和 前一个回调函数运行时发生的错误
    // error 
});



因为promise抛出的错误不会传递到外层,当使用第一种写法时,成功回调的错误无法处理,因此建议使用catch方法。

  // ------------    好的写法    ------------

new Promise((resolve) => {

console.log("Step 1");
setTimeout(() => {
  resolve("100");
}, 1000);

})

.then((value) => {
  // value => 100
//返回一个promise对象
  return new Promise((resolve) => {
    console.log("Step 1-1");
    setTimeout(() => {
      resolve("110");
    }, 1000);
  });
})
.then((value) => {
  // value => 110
  console.log("Step 1-2");
  return value;
})
.then((value) => {
  // value => 110
  console.log("Step 1-3");
  return value;
})
.then((value) => {
  console.log(value); // value = 110
  console.log("Step 2");
});


//then方法中,永远return或throw
//------------    不好的写法    ------------------
promise.then(function () {
getUserInfo(userId);
}).then(function () {
// 在这里可能希望在这个回调中使用用户信息,但你可能会发现它根本不存在
});
如果要使用链式then,必须返回一个promise对象。
//改造
return new Promise((resolve) => {
    console.log("Step 1-1");
   getUserInfo(userId);
  });

asycn/await与promise简单比较

不使用async/await

  function takelongtime() {
    return new Promise(resolve =>{
      setTimeout(()=> resolve('hhhhhh'),1000)})
  }

takelongtime().then(value => console.log('kkkkkk',value)

使用async/await

   function takelongtime() {
    return new Promise(resolve =>{
      setTimeout(()=> resolve('hhhhhh'),1000)})
  }

async function test() {
    const value = await takelongtime();
     console.log(value)
  }

test()

结论

1、async/await的优势在于处理then链
Promise通过then链来解决多层回调问题,但如果需要同时处理由多个Promise组成的then链,就可以用async/await来进一步优化

2、async/await优点:代码更加简洁。

场景:

假设一个场景,分多个步骤完成,每个步骤都是异步的,而且依赖于上一个步骤的结果

function takeLongTime(n) {
    return new Promise(resolve => {
        setTimeout(() => resolve(n + 200), n);
    });
}

function step1(n) {
    console.log(`step1 with ${n}`);
    return takeLongTime(n);
}

function step2(n) {
    console.log(`step2 with ${n}`);
    return takeLongTime(n);
}

function step3(n) {
    console.log(`step3 with ${n}`);
    return takeLongTime(n);
}


用Promise方法来实现这几个步骤的处理:

function doIt() {
    console.time("doIt");
    const time1 = 300;
    step1(time1)
        .then(time2 => step2(time2))
        .then(time3 => step3(time3))
        .then(result => {
            console.log(`result is ${result}`);
            console.timeEnd("doIt");
        });
}

doIt();

// step1 with 300
// step2 with 500
// step3 with 700
// result is 900
// doIt: 1580.487ms


用async/await来实现

async function doIt() {
    console.time("doIt");
    const time1 = 300;
    const time2 = await step1(time1);
    const time3 = await step2(time2);
    const result = await step3(time3);
    console.log(`result is ${result}`);
    console.timeEnd("doIt");
}

doIt();

后续步骤需要多个返回值:

function takeLongTime(n) {
    return new Promise(resolve => {
        setTimeout(() => resolve(n + 200), n);
    });
}

function step1(n) {
    console.log(`step1 with ${n}`);
    return takeLongTime(n);
}

function step2(m, n) {
    console.log(`step2 with ${m} and ${n}`);
    return takeLongTime(m + n);
}

function step3(k, m, n) {
    console.log(`step3 with ${k}, ${m} and ${n}`);
    return takeLongTime(k + m + n);
}

用promise处理,就会发现处理返回值会比较麻烦

function doIt() {
    console.time("doIt");
    const time1 = 300;
    step1(time1)
        .then(time2 => {
            return step2(time1, time2)
                .then(time3 => [time1, time2, time3]);
        })
        .then(times => {
            const [time1, time2, time3] = times;
            return step3(time1, time2, time3);
        })
        .then(result => {
            console.log(`result is ${result}`);
            console.timeEnd("doIt");
        });
}

doIt();



用async/await处理:

async function doIt() {
    console.time("doIt");
    const time1 = 300;
    const time2 = await step1(time1);
    const time3 = await step2(time1, time2);
    const result = await step3(time1, time2, time3);
    console.log(`result is ${result}`);
    console.timeEnd("doIt");
}

doIt();

// step1 with 300
// step2 with 800 = 300 + 500
// step3 with 1800 = 300 + 500 + 1000
// result is 2000
// doIt: 2907.387ms


结论2:
2、async/await的优点:解决promise传递参数太麻烦的问题。

3、async/await使用try...catch处理rejected状态


async function myFunction() {
  try {
    await somethingThatReturnsAPromise();
  } catch (err) {
    console.log(err);
  }
}

// 另一种写法

async function myFunction() {
  await somethingThatReturnsAPromise().catch(function (err){
    console.log(err);
  });
}


异步加载图片
用promise实现异步加载图片的例子


function loadImageAsync(url) {
    return new Promise((resolve, reject) => {
      const image = new Image();
      image.onload = () => {
        resolve(image);
      };
      image.onerror = () => {
        reject(new Error('Could not load image at ' + url));
      };
      image.src = url;
    });
}
const loadImage = loadImageAsync(url);


[参考链接]https://juejin.im/post/5d7de1cc6fb9a06af471f1a7
[参考链接]https://juejin.im/post/5d42970bf265da03c34bdb95

你可能感兴趣的:(手写promise---从promise到asycn/await)