Magren

Magren

Idealist & Garbage maker 🛸
twitter
jike

es6中的promise

Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。

有了 Promise 对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise 对象提供统一的接口,使得控制异步操作更加容易。

Promise 也有一些缺点:

  1. 首先,无法取消 Promise,一旦新建它就会立即执行,无法中途取消。
  2. 如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。
  3. 当处于 pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

promise 的特点#

  1. 对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。
  2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 的对象状态改变,要么是成功,要么就是失败,只要发生这两种情况,状态就会凝固,称为 resolvd(已定型)。改变发生后,再添加回调函数,也是会得到这个结果。

用法#

创造 Promise 实例#

Promise 对象是一个构造函数,用来生成 Promise 实例。

const promise = new Promise(function(resolve, reject) {
  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

resolve 函数的作用是,将 Promise 对象的状态从 “未完成” 变为 “成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

reject 函数的作用是,将 Promise 对象的状态从 “未完成” 变为 “失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

then 方法#

接着用then方法指定 resolved 状态和 rejected 状态的回调函数:

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

第一个函数是状态对象变为 rejected 的调用,第二个是 resolved 的调用,第二个函数是可选的。

then 方法返回的是一个新的 Promise 实例(注意,不是原来那个 Promise 实例)。因此可以采用链式写法,即 then 方法后面再调用另一个 then 方法。

promise.then(function(value) {
  
}.then(function (comments) {
  console.log("resolved: ", comments);
}, function (err){
  console.log("rejected: ", err);
});

catch 方法#

用于指定发生错误时的回调函数。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
}).catch(function(error) {
  // 处理发生的错误
  console.log('发生错误!', error);
});

如果异步操作抛出错误,状态就会变为 rejected,就会调用 catch () 方法指定的回调函数,处理这个错误。另外,then () 方法指定的回调函数,如果运行中抛出错误,也会被 catch () 方法捕获。

跟传统的 try/catch 代码块不同的是,如果没有使用 catch () 方法指定错误处理的回调函数,Promise 对象抛出的错误不会传递到外层代码,即不会有任何反应。

finally 方法#

用于指定不管 Promise 对象最后状态如何,都会执行的操作。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
}).catch(function(error) {
  // 处理发生的错误
  console.log('发生错误!', error);
}).finally(function(){
    alert("finish");
});

finally 方法的回调函数不接受任何参数, 意味着无法知道最终的状态是怎样的。

Jquery、Ajax、Promise 示例#

之前学了 Jquery 和 ajax,就顺手在网上随便找了个 api 测试下:

const apiUrl = "https://suggest.taobao.com/sug?code=utf-8&q=电脑&callback=cb";
$("##bt").click(apiUrl,function(event){
     const promise = new Promise(function(resolve,reject){
       $.ajax({
           url: event.data,
           type:"get",
           dataType:"jsonp",
           headers: {      
                       Accept: "application/json; charset=utf-8",
                   },
           success: function(data) {
            resolve(data);   
           },
           error: function(XMLHttpRequest, textStatus, errorThrown) {
               reject(XMLHttpRequest,textStatus,errorThrown)
           },
       })
   })

   promise.then(function(data){
       console.log(data);
       let x = data.result;
       for(let i = 0 ; i<data.result.length;i++){
           console.log(x[i][0]);
       }
   },function(XMLHttpRequest, textStatus, errorThrown){
       alert(XMLHttpRequest);
       alert(textStatus);
       alert(errorThrown);
   }).catch(function(error){
       console.log(error);
   }).finally(function(){
       alert("finish");
   });
});

结果:

遇到的问题#

其实在 Promise 基础的学习上没有什么太大的问题,但是在 ajax 请求的时候遇上了一个跨域的问题,就是:

Access to XMLHttpRequest at ‘这里是 api’ from origin ‘null’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

这是什么啊……
简单的了解了下,先说说跨域的概念吧

每个网站只能读取同一来源的数据,这里的同一来源指的是主机名 (域名)、协议 (http/https) 和端口号的组合。在没明确授权的情况下,不能读写对方的资源,它是浏览器最核心也最基本的安全功能;只要有一个不一样就跨域。

而 Ajax 的 XMLHttpRequest 受到了同源限制,只能访问同源下的数据,所以就报这个错。
所以怎么还没说怎么解决嗷???

在搜到的文章里面大部分都是后端配合设置一个请求权限,但是我这是野生的 api。。。我还腆着脸去要求别人做这做那哦?

直到我找到个方法,jsonp

jsonp:

  • 通过 script 标签引入某些数据,是同步模式的,用 script 标签做跨域的时候,不建议将数据提前加载,需要按需加载;
  • 当需要数据的时候创建一个 script 标签,将需要的数据放在 src 中,通过 onload 去监听是否请求过来,请求完毕就调用传回来的数据(异步加载);
  • jsonp 不能用 post 请求,只能是 get 请求;

所以为啥这个类型就可以跨域了???

带 src 属性 script、img、iframe、link 等标签是不需要遵守同源策略的,但是通过 src 加载的资源,浏览器限制了 javascript 的权限,能读不能写

综上所述:把 dataType 类型从 json 改成 jsonp 就可以了。

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。