Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mdx #13

Closed
wants to merge 3 commits into from
Closed

mdx #13

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions content/blog/posts/flatmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ title: "谈谈 flatMap"
date: "2017-11-25T22:12:03.284Z"
---
前一阵子在 Twitter 上看到 GitHub 上✨星星✨最多的 Sindre Sorhus 分享了一段 Swift 代码

```swift
// view.subviews(ofType: BoxView.self)
fun subviews<T: NSView>(ofType type: T.Type) -> [T] {
Expand Down Expand Up @@ -78,7 +79,7 @@ public class Main {
}
```

这里的 Optional 是一个通过泛型包裹其他类型的容器。Optional<T> 可以包裹类型为 T 的对象,也可以是空。
这里的 Optional 是一个通过泛型包裹其他类型的容器。`Optional<T>` 可以包裹类型为 T 的对象,也可以是空。

`flatMap` 在这套 api 里起到了传递 Optional 的作用。观察 `flatMap` 接受的函数的类型都是 `T->Optional<U>` ,也就是说这个操作符拿到 Optional 容器内的值,然后返回了一个新的 Optional 容器,其中包含的值的类型未必和原先的一致。由于空对象不再以 `null` 的形式出现,而是被包在了 Optional 容器之中,这样就可以链式调用,避免空指针异常。如果在调用的过程中有一个 Optional 中为空值,则最终返回通过 `orElse` 提供的默认值。

Expand Down Expand Up @@ -150,7 +151,7 @@ RxTextView.textChanges(etSearch)

## 参考资料
* https://repl.it/@yujinyan1992/RxJS-vs-Array-Methods
* https://repl.it/@yujinyan1992/Learning-Swift`
* https://repl.it/@yujinyan1992/Learning-Swift
* https://www.natashatherobot.com/swift-2-flatmap/
* https://gist.github.com/samgiles/762ee337dff48623e729
* [Swift 烧脑体操(四) - map 和 flatMap](http://www.infoq.com/cn/articles/swift-brain-gym-map-and-flatmap)
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ date: "2021-01-24T23:14:03.284Z"
issueId: "4"
---



## `suspend` 是回调(Callback)

理解 `suspend` 其实不需要纠结神奇的「挂起」是什么意思或者拘泥于线程是怎么切换的。实际上 `suspend` 的背后是大家非常熟悉的回调。
Expand Down Expand Up @@ -89,9 +91,15 @@ suspend fun postItem(item: Item) {
// 1.脱掉了 suspend 关键字
// 2.增加了一个 Continuation 对象
fun postItem(item: Item, cont: Continuation) {
// 初始化一个对应调用这次 postItem 的状态机
// 判断传入的是否是 postItem 的 `ContiuationImpl`
// false: 初始化一个对应调用本次 postItem 的状态机
// true: 对应 postItem 内其他 suspend 函数回调回来情况
// 其中 ThisSM 指的 object: ContinuationImpl 这个匿名类
val sm = (cont as? ThisSM) ?: object: ContinuationImpl {
fun resume(..) {
// 实际源码中 override 的是
// kotlin.coroutine.jvm.internal.BaseContinuationImpl
// 的 invokeSuspend 方法
override fun resume(..) {
// 通过 ContinuationImpl.resume
// 重新回调回这个方法
postItem(null, this) // highlight-line
Expand All @@ -116,12 +124,18 @@ fun postItem(item: Item, cont: Continuation) {
createPost(token, item, sm)
case 2:
procesPost(post)
// ...
}
}
```

编译器将 `suspend` 编译成带有 continuation 参数的方法叫做 CPS (Continuation-Passing-Style) 变换。

<div className="callout mono">
可以写一段简单的 `suspend` 函数,然后通过 IntelliJ IDEA / Android Studio 的 Tools -> Kotlin -> Show Kotlin Bytecode (Decompile) 查看 Kotlin 生成的状态机代码。
</div>


## 使用 `suspend` 函数无须关心线程切换

`suspend` 提供了这样一个**约定(Convention)**:调用这个函数不会阻塞当前调用的线程。这对 UI 编程是非常有用的,因为 UI 的主线程需要不断相应各种图形绘制、用户操作的请求,如果主线程上有耗时操作会让其他请求无法及时响应,造成 UI 卡顿。
Expand Down
6 changes: 4 additions & 2 deletions gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ module.exports = {
},
},
{
resolve: `gatsby-transformer-remark`,
resolve: `gatsby-plugin-mdx`,
options: {
plugins: [
extensions: ['.md', '.mdx'],
gatsbyRemarkPlugins: [
{
resolve: `gatsby-remark-images`,
options: {
Expand All @@ -47,6 +48,7 @@ module.exports = {
`gatsby-remark-prismjs`,
`gatsby-remark-copy-linked-files`,
`gatsby-remark-smartypants`,
// `gatsby-remark-attr`
],
},
},
Expand Down
6 changes: 3 additions & 3 deletions gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ exports.createPages = async ({ graphql, actions }) => {
const result = await graphql(
`
{
allMarkdownRemark(
allMdx(
sort: { fields: [frontmatter___date], order: DESC }
limit: 1000
) {
Expand All @@ -32,7 +32,7 @@ exports.createPages = async ({ graphql, actions }) => {
}

// Create blog posts pages.
const posts = result.data.allMarkdownRemark.edges
const posts = result.data.allMdx.edges

posts.forEach((post, index) => {
const previous = index === posts.length - 1 ? null : posts[index + 1].node
Expand All @@ -53,7 +53,7 @@ exports.createPages = async ({ graphql, actions }) => {
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions

if (node.internal.type === `MarkdownRemark`) {
if (node.internal.type === `Mdx`) {
const value = createFilePath({ node, getNode })
createNodeField({
name: `slug`,
Expand Down
Loading