浅析前端异常及降级处理

发表于 3年以前  | 总阅读数:249 次

一、导读

“异常”一词出自《后汉书.卷一.皇后纪上.光烈阴皇后纪》,表示非正常的,不同于平常的。在我们现实生活中同样处处存在着异常,比如小县城里的路灯年久失修...,上下班高峰期深圳的地铁总是那么的拥挤...,人也总是时不时会生病等等; 由此可见,这个世界错误无处不在,这是一个基本的事实。

而在计算机的世界中,异常指的是在程序运行过程中发生的异常事件,有些错误是由于外部环境导致的,有些错误是由于开发人员疏忽所导致的,有效的处理这些错误,保证计算机世界的正常运转是我们开发人员必不可少的一环。

二、背景

随着项目的不断壮大,客户的不断接入,项目的稳定性成为团队的一大挑战。

当用户或者团队测试人员遇到问题时,大概率是直接丢给开发人员一张白屏页面或错误UI的截图,且该错误并不是必现时,让前后端同学定位问题倍感头痛。有没有一种方式既能够提升用户体验,又能够帮助开发人员快速定位解决问题?

本着“客户就是上帝”的商业准则,为用户创造良好的用户体验,是前端开发者职责之所在。当页面发生错误的时候,相比于页面崩溃或点不动,在适当的时机,以一种适当的方式去提醒用户当前发生了什么,无疑是一种更友好的处理方式。

项目中面临下面几种异常场景,需要处理:

  • 语法错误
  • 事件异常
  • HTTP请求异常
  • 静态资源加载异常
  • Promise 异常
  • Iframe 异常
  • 页面崩溃

整体异常处理方案需要实现二方面的效果:

  1. 提升用户体验
  2. 上报监控系统,能及时早发现、定位、解决问题

下面我们先从几个异常场景出发,逐步探讨如何解决这些异常并给予更好的用户体验。

三、错误类型

在探讨具体的解决方案之前,我们先来认识和熟悉一下前端的各种错误类型。

ECMA-262规范定义的七种错误类型:

  • Error
  • EvalError
  • RangeError
  • ReferenceError
  • SyntaxError
  • TypeError
  • URIError

Error

Error是所有错误的基类,其他错误都继承自该类型

EvalError

EvalError对象表示全局函数eval()中发生的错误。如果eval()中没有错误,则不会抛出该错误。可以通过构造函数创建这个对象的实例

image.png

RangeError

RangeError对象表示当一个值不在允许值的集合或范围内时出现错误。

image.png

ReferenceError

当引用不存在的变量时,该对象表示错误:

image.png

SyntaxError

当JavaScript引擎在解析代码时遇到不符合该语言语法的标记或标记顺序时,将引发该异常:

image.png

TypeError

传递给函数的操作数或实参与该操作符或函数期望的类型不兼容:

image.png

URIError

当全局URI处理函数以错误的方式使用时:

image.png

四、处理和防范

上文我们提到错误和异常无处不在,存在于各式各样的应用场景中,那我们应该如何有效的拦截异常,将错误扼杀于摇篮之中,让用户无感呢?亦或者遇到致命错误时,进行降级处理?

(1) try catch

1.语法

ECMA-262 第 3 版中引入了 try-catch作为 JavaScript 中处理异常的一种标准方式,基本的语法如下所示。

try {
  // 可能会导致错误的代码
} catch (error) {
  // 在错误发生时怎么处理
}
复制代码

2.动机

使用try...catch来捕获异常,我归纳起来主要有两个动机:

1)是真真正正地想对可能发生错误的代码进行异常捕获;

2)我想保证后面的代码继续运行。

动机一没什么好讲的,在这里,我们讲讲动机二。假如我们有以下代码:

console.log(foo); //foo未定义
console.log('I want running')
复制代码

代码一执行,你猜怎么着?第一行语句报错了,第二行语句的log也就没打印出来。如果我们把代码改成这样:

try{ 
    console.log(foo)
}catch(e){
    console.log(e)
}
console.log('I want running');
复制代码

以上代码执行之后,虽然还是报了个ReferenceError错误,但是后面的log却能够被执行。

从这个示例,我们可以看出,一旦前面的(同步)代码出现了没有被开发者捕获的异常的话,那么后面的代码就不会执行了。所以,如果你希望当前可能出错的代码块后续的代码能够正常运行的话,那么你就得使用try...catch来主动捕获异常。

扩展:

实际上,出错代码是如何干扰后续代码的执行,是一个值得探讨的主题。下面进行具体的探讨。因为市面上浏览器众多,对标准的实现也不太一致。所以,这里的结论仅仅是基于Chromev91.0.4472.114。探讨过程中,我们涉及到两组概念:同步代码与异步代码,代码书写期和代码运行期。

场景一:同步代码(出错) + 同步代码

1625024247(1).png

可以看到,出错的同步代码后面的同步代码不执行了。

场景二:同步代码(出错) + 异步代码

1625024396(1).png

跟上面的情况一下,异步代码也受到影响,也不执行了。

场景三:异步代码(出错) + 同步代码

image.png

可以看到,异步代码出错,并不会影响后面同步代码的执行。

场景四:异步代码(出错) + 异步代码

image.png

出错的异步代码也不会影响后面异步代码的执行。

如果只看场景一二三,很容易得出如下结论:在代码运行期,同步代码始终是先于异步代码执行的。如果先执行的同步代码没有出错的话,那么后面的代码就会正常执行,否则后面的代码就不会执行。但场景四却打破了这个结论。我们不妨继续看看场景五。

场景五:异步代码 + 同步代码(出错) + 异步代码

image.png

看到了没?同样是异步代码,按理说,代码运行期,如果你是受出错的同步代码的影响的话,那你要么是两个都不执行,或者两个都执行啊?凭什么写在出错代码代码书写期前面的异步代码就能正常执行,而写在后面的就不执行呢?经过验证,在firefoxv75.0版本中也是同样的表现。

所以,到了这里,我们基本上可以得出这样的结论:运行期,一先一后的两个代码中,出错的一方代码是如何影响另外一方代码继续执行的问题中,跟异步代码没关系,只跟同步代码有关系;跟代码执行期没关系,只跟代码书写期有关系。

说人话就是,异步代码出错与否都不会影响其他代码继续执行。而出错的同步代码,如果它在代码书写期是写在其他代码之前,并且我们并没有对它进行手动地去异常捕获的话,那么它就会影响其他代码(不论它是同步还是异步代码)的继续执行。

综上所述,如果我们想要保证某块可能出错的同步代码后面的代码继续执行的话,那么我们必须对这块同步代码进行异常捕获。

3.范围

只能捕获同步代码所产生的运行时错误,对于语法错误和异步代码所产生的错误是无能为力的。

当遇到语法错误时:

当遇到异步运行时错误时:

(2) Promise.catch()

1.语法

const promise1 = new Promise((resolve, reject) => {
  throw 'Uh-oh!';
});

promise1.catch((error) => {
  console.error(error);
});
// expected output: Uh-oh!
复制代码

2.动机

用来捕获promise代码中的错误

3.范围

使用Promise.prototype.catch()我们可以方便的捕获到异常,现在我们来测试一下常见的语法错误、代码错误以及异步错误。

当遇到代码错误时,可以捕获:

当遇到语法错误时,不能捕获:

当遇到异步运行时错误时,不能捕获:

1625033576(1).png

(3) unhandledrejection

1.用法

unhandledrejection:当Promise 被 reject 且没有 reject 处理器的时候,会触发 unhandledrejection 事件

window.addEventListener("unhandledrejection", function(e){
  console.log(e);
});
复制代码

2.动机

为了防止有漏掉的 Promise 异常,可以在全局增加一个对 unhandledrejection 的监听进行兜底,用来全局监听Uncaught Promise Error。

3.范围

  window.addEventListener("unhandledrejection", function (e) {
      console.log("捕获到的promise异常:", e);
      e.preventDefault();
    });
    new Promise((res) => {
      console.log(a);
    });
    // 捕获到的promise异常的: PromiseRejectionEvent
复制代码

注意:此段代码直接写在控制台是捕获不到promise异常的,写在html文件中可正常捕获。

(4) window.onerror

1.用法

当 JS 运行时错误发生时,window 会触发一个 ErrorEvent 接口的 error 事件,并执行 window.onerror()。

window.onerror = function(message, source, lineno, colno, error) {
   console.log('捕获到异常:',{message, source, lineno, colno, error});
}
复制代码

2.动机

众所周知,很多做错误监控和上报的类库就是基于这个特性来实现的,我们期待它能处理那些try...catch不能处理的错误。

3.范围

根据MDN的说法,wondow.onerror能捕获JavaScript运行时错误(包括语法错误)或一些资源错误。而在真正的测试过程中,wondow.onerror并不能捕获语法错误。

image.png

经测试,window.onerror并不能捕获语法错误和静态资源的加载错误。同样也不能捕获异步代码的错误,但是有一点值得注意的是,window.onerror能捕获同样是异步代码的setTimeout和setInterval里面的错误。

看来,寄予厚望的window.onerror并不是万能的。

(5) window.addEventListener

1.用法

window.addEventListener('error',(error)=>{console.log(error)})
复制代码

2.动机

当然是希望用他来兜住window.onerror和try catch的底,希望他能捕获到异步错误和资源的加载错误。

3.范围

  <body>
    <img id="img" src="./fake.png" />
    <iframe id="iframe" src="./test4.html"></iframe>
  </body>
  <script>
    window.addEventListener(
      "error",
      function (error) {
        console.log(error, "error");
      },
      true
    );
    setTimeout(() => {
      console.log(a);
    });
    new Promise((resolve, reject) => {
      console.log(a);
    });
    console.log(b)
    var f=e, //语法异常
  </script>
复制代码

在此过程中,资源文件都是不存在的,我们发现window.addEventListener('error')依旧不能捕获语法错误,Promise异常和iframe异常。

对于语法错误我们可以在编译过程中捕获,,Promise异常已在上文中给出解决方案,现在还剩下iframe异常需要单独处理了。

(5) iframe异常

1.用法

window.frames[0].onerror = function (message, source, lineno, colno, error) {
    console.log('捕获到 iframe 异常:',{message, source, lineno, colno, error});
    return true;
};
复制代码

2.动机

用来专门捕获iframe加载过程中的异常。

3.范围

很遗憾,结果并不令人满意,在实际的测试过程中,该方法未能捕获到异常。

(6) React中捕获异常

部分 UI 的 JavaScript 错误不应该导致整个应用崩溃,为了解决这个问题,React 16 引入了一个新的概念 —— 错误边界。

错误边界是一种 React 组件,这种组件可以捕获并打印发生在其子组件树任何位置的 JavaScript 错误,并且,它会渲染出备用 UI,而不是渲染那些崩溃了的子组件树。错误边界在渲染期间、生命周期方法和整个组件树的构造函数中捕获错误。

注意:错误边界无法捕获以下场景中产生的错误

  • 事件处理
  • 异步代码(例如 setTimeout 或 requestAnimationFrame 回调函数)
  • 服务端渲染
  • 它自身抛出来的错误(并非它的子组件)

如果一个 class 组件中定义了 static getDerivedStateFromError() 或 componentDidCatch() 这两个生命周期方法中的任意一个(或两个)时,那么它就变成一个错误边界。当抛出错误后,请使用 static getDerivedStateFromError() 渲染备用 UI ,使用 componentDidCatch() 打印错误信息。

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // 更新 state 使下一次渲染能够显示降级后的 UI
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // 你同样可以将错误日志上报给服务器
    logErrorToMyService(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // 你可以自定义降级后的 UI 并渲染
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children; 
  }
}
复制代码

错误边界的工作方式类似于 JavaScript 的 catch {},不同的地方在于错误边界只针对 React 组件。只有 class 组件才可以成为错误边界组件。大多数情况下, 你只需要声明一次错误边界组件, 并在整个应用中使用它。

以上引用自React 官网。

(7) Vue中捕获异常

Vue.config.errorHandler = function (err, vm, info) {
  // handle error
  // `info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
  // 只在 2.2.0+ 可用
}
复制代码

指定组件的渲染和观察期间未捕获错误的处理函数。这个处理函数被调用时,可获取错误信息和 Vue 实例。

  • 从 2.2.0 起,这个钩子也会捕获组件生命周期钩子里的错误。同样的,当这个钩子是 undefined 时,被捕获的错误会通过 console.error 输出而避免应用崩溃。
  • 从 2.4.0 起,这个钩子也会捕获 Vue 自定义事件处理函数内部的错误了。
  • 从 2.6.0 起,这个钩子也会捕获 v-on DOM 监听器内部抛出的错误。另外,如果任何被覆盖的钩子或处理函数返回一个 Promise 链 (例如 async 函数),则来自其 Promise 链的错误也会被处理。

以上引用自Vue 官网。

(8) http请求异常

1.用法

以axios为例,添加响应拦截器

axios.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    // response 是请求回来的数据
    return response;
  }, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error)
  }
)

复制代码

2.动机

用来专门捕获HTTP请求异常

五、项目实践

在提出了这么多的解决方案之后,相信大家对具体怎么用还是存在一些疑惑。那么接下来,我们真正的进入实践阶段吧!

我们再次回顾一下我们需要解决的问题是什么?

  • 语法错误
  • 事件异常
  • HTTP请求异常
  • 静态资源加载异常
  • Promise 异常
  • Iframe 异常
  • 页面崩溃

捕获异常是我们的最终目标吗?并不是,回到解决问题的背景下,相比于页面崩溃或点不动,在适当的时机,以一种适当的方式去提醒用户当前发生了什么,无疑是一种更友好的处理方式。

结合到项目中,具体实践起来有如下两种方案:

  • 1.代码中通过大量的try catch/Promise.catch来捕获,捕获不到的使用其他方式进行兜底
  • 2.通过框架提供的机制来做,再对不能捕获的进行兜底

方案一无疑不是很聪明的样子...这意味着要去改大量的原有代码,心智负担成倍数增加。方案二则更加明智,通过在底层对错误进行统一处理,无需变更原有逻辑。

到项目中,使用的是React框架,React正好提供了一种捕获异常的机制(上文已提及)并做降级处理,但是细心的小伙伴发现了,react并不能捕获如下四种错误:

  • 事件处理
  • 异步代码(例如 setTimeout 或 requestAnimationFrame 回调函数)
  • 服务端渲染
  • 它自身抛出来的错误(并非它的子组件)

对于第三点服务端渲染错误,项目中并没有适用的场景,此次不做重点分析。我们重点分析第一点和第二点。

我在这里先抛出几个问题,大家先做短暂的思考:

  • 1.若事件处理和异步代码的错误导致页面crash,我们该如何预防?
  • 2.如何对ErrorBounary进行兜底?相比一个按钮点击无效,如何更加友好的提示用户?

先来看第一个问题,若事件处理和异步代码的错误导致页面崩溃:

const Test = () => {
  const [data, setData] = useState([]);
  return (
    <div
      onClick={() => {
        setData('');
      }}
    >
      {data.map((s) => s.i)}
    </div>
  );
};
复制代码

此段代码在正常渲染期间是没问题的,但在触发了点击事件之后会导致页面异常白屏,如果在外面套上我们的ErrorBounday组件,情况会是怎么样呢?

答案是依然能够捕获到错误,并能够对该组件进行降级处理!

此时有些小伙伴已经察觉到了,错误边界只要是在渲染期间都是可以捕获错误的,无论首次渲染还是二次渲染。流程图如下:

image.png

第一个问题原来根本就不是问题,这本身就是一个闭环,不用我们解决!

再来看看第二个问题:

对于事件处理和异步代码中不会导致页面崩溃的代码:

const Test = () => {
  return (
    <button
      onClick={() => {
        [].map((s) => s.a.b);
      }}
    >
      点击
    </button>
  );
};
复制代码

button按钮可正常点击,但是该点击事件的内部逻辑是有问题的,导致用户点击该按钮本质是无效的。此时若不及时给与友好提示,用户只会陷入抓狂中....

那么有没有办法对ErrorBoundary进行兜底呢?即可以捕获异步代码或事件处理中的错误。

上文提到的window.addEventListener('error')正好可以解决这个问题。理想状态下:

而真正的执行顺序确实这样的:

1625105438(1).png

在真正执行的过程中,window.addEventListener('error')是先于ErrorBoundary捕获到错误的,这就导致当error事件捕获到错误时,他并不知道该错误是否会导致页面崩溃,不知道该给予怎样的提示,到底是对页面进行降级处理还是只做简单的报错提示?

问题似乎就卡在这了....

那能否通过一种有效的途径告诉error事件:ErrorBoundary已经捕获到了错误,你不需要处理!亦或者是ErrorBoundary未能捕获到错误,这是一个异步错误/事件错误,但不会引起页面崩溃,你只需要提示用户!

答案肯定是有的,比如建立一个nodeJs服务器,通过webSocket去通知,但是这样做不仅麻烦,还会有一定的延迟。

在笔者苦思冥想之际,在某个静悄悄的夜晚,突然灵感一现。为什么我们非要按照他规定的顺序执行呢?我们能不能尝试改变他的执行顺序,让错误捕获回到我们理想中的流程来呢?

改变思路之后,我们再思考有什么能改变代码执行顺序吗?没错,异步事件!

  window.addEventListener('error', function (error) {
        setTimeout(()=>{
          console.log(error, 'error错误');
        })
      });
复制代码

当给error事件的回调函数加入setTimeout后,捕获异常的流程为:

image.png

现在就可以通知error事件到底页面崩溃了没有,到底需不需要它的处理!上代码:

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // 更新 state 使下一次渲染能够显示降级后的 UI
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // 你同样可以将错误日志上报给服务
    logErrorToMyService(error, errorInfo);

    //告诉error事件 ErrorBoundary已处理异常
     localStorage.setItem("ErrorBoundary",true)
  }

  render() {
    if (this.state.hasError) {
      // 你可以自定义降级后的 UI 并渲染
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children; 
  }
}
复制代码
window.addEventListener('error', function (error) {
        setTimeout(() => {
          //进来代表一定有错误 判断ErrorBoundary中是否已处理异常
          const flag = localStorage.getItem('ErrorBounary');
          if (flag) {
            //进入了ErrorBounary 错误已被处理 error事件不用处理该异常
            localStorage.setItem('ErrorBounary', false); //重置状态
          } else {
            //未进入ErrorBounary 代表此错误为异步错误/事件错误
            logErrorToMyService(error, errorInfo);  // 你可以将错误日志上报给服务
            //判断具体错误类型
            if (error.message.indexOf('TypeError')) {
              alert('这是一个TypeError错误,请通知开发人员');
            } else if (error.message.indexOf('SyntaxError')) {
              alert('这是一个SyntaxError错误,请通知开发人员');
            } else {
              //在此次给与友好提示
            }
          }
        });
      });
复制代码

最后,通过我们的努力,当页面崩溃时,及时进行降级处理;当页面未崩溃,但有错误时,我们及时的告知用户,并对错误进行上报,达到预期的效果。

六、扩展

1.设置采集率

若是错误实在太多,比如有时候代码进入死循环,错误量过多导致服务器压力大时,可酌情降低采集率。比如采集30%:

  if (Math.random() < 0.3) {
        //上报错误
        logErrorToMyService(error, errorInfo);
      }
复制代码

2.提效

解决上面这些问题后,大家难免会有疑问:那每一个组件都要去套一层ErrorBoundary组件,这工作量是不是有点大....而且有一些老代码,嵌套的比较深,改起来心理负担也会比较大。那有没有办法将其作为一个配置项,配置完之后,编译时自动套上一层ErrorBoundary组件呢?这个我们下次在做探讨!

3.可配置

能否将ErrorBoundary扩展成可传入自定义UI的组件呢?这样大家通过定制化UI,在不同的场景进行不同的降级处理。

同样,这一块我们下次再讨论!

七、总结

异常处理是高质量软件开发中的一个基本部分,但是在许多情况下,它们会被忽略,或者是不正确的使用,而处理异常只是保证代码流程不出错,重定向到正确的程序流中去。

本文从前端错误类型出发,从try catch逐步揭开错误异常神秘的面纱,再通过一系列的操作对异常进行监控和捕获,最后达到提升用户体验,上报监控系统的效果。

八、思考

  • Promise.catch 和 try catch 捕获异常有什么区别?
  • ErrorBounary内部如何实现?
  • 为什么unhandledrejection写在控制台是捕获不到错误的?而写在HTML文件中就可以捕获到?
  • 服务端渲染错误如何捕获?

带着这些思考,我们下次见~

本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/Ibye2r5UP6V9U8vyMn5pjw

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237231次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8065次阅读
 目录