Тупик в горутине с GopherJS - PullRequest
       18

Тупик в горутине с GopherJS

0 голосов
/ 13 февраля 2020

Почему в следующем коде есть тупик? Я пытаюсь вернуть что-то из программы на улицу

package main

import (
    "fmt"
    "syscall/js"
    "time"
)

func test(this js.Value, i []js.Value) interface{} {
    done := make(chan string, 1)

    go func() {
        doRequest := func(this js.Value, i []js.Value) interface{} {
            time.Sleep(time.Second)

            return 0
        }

        js.Global().Set("doRequest", js.FuncOf(doRequest))
        args := []js.Value{js.ValueOf("url")}
        var x js.Value
        doRequest(x, args)
        done <- "true"
    }()

    aa := <-done
    fmt.Println(aa)

    return 0
}

func main() {
    c := make(chan bool)
    js.Global().Set("test", js.FuncOf(test))
    <-c
}

Когда я запускаю это в браузере и вызываю test (), будет показана следующая ошибка

fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
.....

Ответы [ 2 ]

1 голос
/ 14 февраля 2020

Почти то, что написано в сообщении об ошибке. Все горутины спят. main ничего не запускает и просто получает канал, поэтому он заблокирован, и никакие другие программы не выполняются, поэтому нет никакой возможности, что main когда-либо снова проснется, поэтому среда выполнения паникует.

Если я правильно помню, в отличие от обычного Go, Gopher JS не закрывает все и не завершает работу, если main выходит (частично потому, что: что именно это будет означать? Ближайший аналог программы Go было бы закрыть веб-страницу! Это было бы отстой. Так что Gopher JS этого не делает.). Так что то, что вы делаете, чтобы поддерживать main живым, не обязательно, строго говоря, в Суслике JS.

Тем не менее, если вместо этого вы скажете (например) time.Sleep(time.Hour) в конце, то в то время как все goroutines все еще спят (строго говоря), main в конечном счете проснется, который знает среда выполнения, так что в этом случае он не панирует c.

Что касается вашего фактического test Если вы попробуете эту функцию, вы получите сообщение об ошибке: Uncaught Error: runtime error: cannot block in JavaScript callback, fix by wrapping code in goroutine. test выполняет блокирующий вызов на канале, а Gopher JS не допустит этого в функции, вызываемой непосредственно из Javascript, поэтому он паникует. (Когда я запускаю его на детской площадке , я также получаю Uncaught TypeError: r is not a function, но это просто выпадение из предыдущей ошибки.) Я думаю , что вы пытаетесь сделать, это ждать doRequest до фини sh, напечатайте значение и вернитесь, но это не сработает. Для этого вам нужно будет использовать собственное обещание Javascript или какой-то другой асинхронный механизм.

0 голосов
/ 13 февраля 2020
func main() {
    c := make(chan bool)
    js.Global().Set("test", js.FuncOf(test))
    <-c
}

Вы создали канал c, а затем ждете, чтобы получить значение из него. Обратите внимание, что c является локальной переменной для функции main. Ссылка на c никогда не передается нигде в программе, поэтому на канале c никогда не может быть значения, поэтому ваша основная программа будет ждать вечно.

...