Promise以及各种异步的学习

Promise 是一个对象,用来传递异步操作,代表了某个未来才会知道的结果。

特点:

  • 只有异步操作的结果可以决定这个对象的哪种状态,包括 pending,resolved,rejected,外界无法对它造成影响
  • 一旦状态改变了,就会维持这个结果不会再变,你可以一直拿到这个结果

主要的功能

有了 promise,可以将一些异步操作以同步的形式保存下来,避免层层嵌套

缺点

  • 无法取消
  • 不设置回调,内部的错误就无法反映到外部
  • pending 状态很长,我们不知道是即将完成还是刚刚开始

如果某些事件不断重复发生,可以用 stream 模式

具体的使用

创建实例

var promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

传入一个函数生成 promise 对象,两个参数分别是resolvereject(由 js 引擎提供,不用自己部署)

实例生成过后

then 方法

指定成功以及失败时的回调函数,第二个是可选的,不一定要提供,这个东西可以在 catch 方法中做

promise.then(
  function(value) {
    // success
  },
  function(value) {
    // failure
  }
);

简单的例子

function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms, ‘done’);
});
}

timeout(100).then((value) => {
console.log(value);
});

就是timeout函数 return 的 promise 里面有个定时器,时间到了执行resolve,将‘done’传进去,然后用 then 来指定对应的 resolved,输出传入的 value。

异步加载图片的例子

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

就是在 onload 和 onerror 事件的时候调用 resolved 和 reject

Ajax 操作的例子

var getJSON = function(url) {
  var promise = new Promise(function(resolve, reject) {
    var client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();
    function handler() {
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    }
  });
  return promise;
};
getJSON("/posts.json").then(
  function(json) {
    console.log("Contents: " + json);
  },
  function(error) {
    console.error("出错了", error);
  }
);

就是在监听 statuscode 的时候区分调用了下 resolved 和 reject

resolve 传入 promise 实例

var p1 = new Promise(function(resolve, reject) {
  // ...
});
var p2 = new Promise(function(resolve, reject) {
  // ...
  resolve(p1);
});

这里 p2 的状态依赖 p1 的状态,只有 p1 改变了,p2 才会跟着改变

var p1 = new Promise(function(resolve, reject) {
  setTimeout(() => reject(new Error("fail")), 3000);
});
var p2 = new Promise(function(resolve, reject) {
  setTimeout(() => resolve(p1), 1000);
});
p2.then(result => console.log(result));
p2.catch(error => console.log(error));
// Error: fail
  • 这里 p2 在 1 秒后调用 resolve,但是 p1 没变,所以等待;
  • 3 秒后,p1 变成 reject,p2 也就变成了 reject
  • 这里返回的结果 p3 是可以拿得到的

then 方法

then方法返回的是一个新的 promise 的实例

所以可以链式写法,在 then 之后再调用 then

getJSON("/post/1.json")
  .then(function(post) {
    return getJSON(post.commentURL);
  })
  .then(
    function funcA(comments) {
      console.log("Resolved: ", comments);
    },
    function funcB(err) {
      console.log("Rejected: ", err);
    }
  );

catch 方法

catch 其实就是一个.then(null,rejection)

getJSON("/post/1.json")
  .then(function(post) {
    return getJSON(post.commentURL);
  })
  .then(function(comments) {
    // some code
  })
  .catch(function(error) {
    // 处理前面三个Promise产生的错误
  });

这里的话,有 3 个 promise,getJSON 本身,然后两个 then 方法得到的 promose,这里的抛出的错误,以及变化成 rejected 都是可以在最后被 catch 住的。

  • catch 是会冒泡的,只要在最后写个 catch 就能拿到
  • catch 返回的还是一个 promise
  • Promise 的错误不会传递到外层代码,如果不 catch,直接消失
var promise = new Promise(function(resolve, reject) {
  resolve("ok");
  setTimeout(function() {
    throw new Error("test");
  }, 0);
});
promise.then(function(value) {
  console.log(value);
});
// ok
// Uncaught Error: test

这里报错是因为 promise 已经执行结束了,这里的错误会被抛出到函数体外,讲道理的话,不会这么写…

process.on("unhandledRejection", function(err, p) {
  console.error(err.stack);
});

nodejs 里面的 unhandledRejection 事件,专门监听未捕获的 reject 错误

all 方法

将多个 promise 的实例,包装成一个新的 promise 实例。(可以不是数组,但是得具有 iterator 接口,且返回的都是 Promise 对象,如果不是,会先调用 Promise.resolve 方法,将参数转化为 Promise 实例)

var p = Promise.all([p1, p2, p3]);
  • 必须全成功才会成功,成功之后,结果会成为数组,传给回调
  • 有一个失败了就失败了,第一个被 reject 的实例的返回值传给 p 的回调

race 方法

var p = Promise.race([p1,p2,p3]);

有一个改变了状态,p 的状态就跟着变,然后他的值会传递给 p 的回调

var p = Promise.race([
  fetch("/resource-that-may-take-a-while"),
  new Promise(function(resolve, reject) {
    setTimeout(() => reject(new Error("request timeout")), 5000);
  })
]);
p.then(response => console.log(response));
p.catch(error => console.log(error));

这里的例子就是加了个 timeout 的设置

resolve 方法

这个方法将现有的对象装化为 promise 对象,可不带参数
就是看有没有 then 方法,如果没有,直接就是状态为 resolved 的 promise

var p = Promise.resolve("Hello");
p.then(function(s) {
  console.log(s);
});
// Hello
  • 如果是 promise 的实例,那就直接返回实例

reject 方法

Promise.reject()返回一个新的 promise,且实例状态为 rejected

var p = Promise.reject("出错了");
// 等同于
var p = new Promise((resolve, reject) => reject("foo"));
p.then(null, function(s) {
  console.log(s);
});

应用

加载图片

const preloadImage = function(path) {
  return new Promise(function(resolve, reject) {
    var image = new Image();
    image.onload = resolve;
    image.onerror = reject;
    image.src = path;
  });
};

异步的四种: 1.回调 2.事件监听 3.发布/订阅
4.Promise 对象

1 最以前就是回调函数了,但是一层层的写,很容易 callback hell
4 所以 promise 可以把代码写成纵向的加载,最大的问题,代码冗余,无论什么,被包装了都是一堆的 then
generator 函数就是将控制权抛了出去

tudo:stream 模式是个啥?
tudo:多个 then 在一起,其中一个出了错,剩下的还会执行吗?还是直接到 catch 的地方?
tudo:如果不 catch,是不是直接挂掉?catch 里面的例子测试一下
tudo:resovle 方法如果有 then 的话会发生什么呢?


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 981909093@qq.com

文章标题:Promise以及各种异步的学习

文章字数:1.5k

本文作者:泽鹿

发布时间:2019-08-28, 16:45:23

最后更新:2019-08-28, 20:06:09

原始链接:http://panyifei.github.io/2019/08/28/前端技术/js/框架以及规范/ECMAScript6/Promise以及各种异步的学习/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏