gpt4 book ai didi

javascript - 如何使用 GJS 安排一系列异步任务之后发生的事情?

转载 作者:行者123 更新时间:2023-11-27 23:57:14 25 4
gpt4 key购买 nike

我正在使用 GJS 和 GNOME 平台使用 JavaScript 编写一个简单的桌面应用程序:GTK+、GLib、Gio、GObject。下面的代码说明了我面临的情况,并且更容易复制,因为它不需要访问应用程序使用的文件。简而言之,我想在完成一系列异步任务(加载一系列文件的内容)之后运行指定的代码行。我怎样才能在 GJS 中做到这一点,最好使用 Gio 或 JavaScript 本身的东西?

#!/usr/bin/gjs

const Lang = imports.lang;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;

const Home = new Lang.Class({
Name: "Home",

// Start snippet 1
_enumerateChildrenAsyncCallback: function(dir, result) {
let fileEnumerator = dir.enumerate_children_finish(result);
let displayName, file, fileInfo, fileType, iter;
while ((fileInfo = fileEnumerator.next_file(null))) {
iter = this.model.append();
displayName = fileInfo.get_display_name();
this.model.set(iter, [0], [displayName], 1);

file = dir.get_child(fileInfo.get_name());
fileType = file.query_file_type(Gio.FileQueryInfoFlags.NONE, null);
if (fileType != Gio.FileType.REGULAR) continue;

file.load_contents_async(null, function(file, result) {
let [success, contents, etag] = file.load_contents_finish(result);
let message = "";
if (success) {
message = "Finished loading file %s";
} else {
message = "Couldn't load file %s";
}
log(message.replace("%s", file.get_basename()));
});
}
},

_init: function() {
this.application = new Gtk.Application();
this.application.connect("activate", Lang.bind(this, this._onActivate));
this.application.connect("startup", Lang.bind(this, this._onStartup));
},

_onActivate: function() {
this._window.show_all();
},

_onStartup: function() {
this.model = new Gtk.ListStore();
this.model.set_column_types([GObject.TYPE_STRING]);
let renderer = new Gtk.CellRendererText();

let dir = Gio.file_new_for_path(GLib.get_home_dir());
dir.enumerate_children_async("standard::*",
Gio.FileQueryInfoFlags.NONE,
GLib.PRIORITY_DEFAULT,
null,
Lang.bind(this, this._enumerateChildrenAsyncCallback),
null);
/*
* I would like this line to be run after all files have been read.
*
*/
this.model.set_sort_column_id(0, Gtk.SortType.ASCENDING);

let column = new Gtk.TreeViewColumn({
title: "Files"
});
column.pack_start(renderer, true);
column.add_attribute(renderer, "text", 0);
let view = new Gtk.TreeView({
model: this.model
});
view.append_column(column);
let scrolled = new Gtk.ScrolledWindow();
scrolled.hscrollbar_policy = Gtk.PolicyType.AUTOMATIC;
scrolled.Vscrollbar_policy = Gtk.PolicyType.AUTOMATIC;
scrolled.add(view);
this._window = new Gtk.ApplicationWindow({
application: this.application,
default_height: 300,
default_width: 400,
title: "Home, sweet home"
});
this._window.add(scrolled);
}
});

let home = new Home();
home.application.run(ARGV);

PS:在提供的代码中,在完成所有异步任务之前运行指定的代码行不会阻止应用程序正常运行。但是,我想在应用程序启动时对列表进行一次排序,而不是在每次读取文件时对列表进行排序。当然,知道如何去做在其他情况下也很有帮助。

最佳答案

如果我正确理解你想要做什么,你需要类似 Promise.all() 的东西。不幸的是,GJS 还没有 Promise 库。

我建议在枚举子回调中执行类似的操作(我编辑了一些与我要说明的内容无关的部分):

_enumerateChildrenAsyncCallback: function(dir, result) {
let fileEnumerator = dir.enumerate_children_finish(result);
let displayName, file, fileInfo, fileType, iter;

let pendingOperations = new Set();

while ((fileInfo = fileEnumerator.next_file(null))) {
file = dir.get_child(fileInfo.get_name());
fileType = file.query_file_type(Gio.FileQueryInfoFlags.NONE, null);
if (fileType != Gio.FileType.REGULAR) continue;

pendingOperations.add(file);

file.load_contents_async(null, (file, result) => {
let [success, contents, etag] = file.load_contents_finish(result);

pendingOperations.delete(file);
if (pendingOperations.size === 0)
this.model.set_sort_column_id(0, Gtk.SortType.ASCENDING);
});
}
},

乍一看,这似乎在 pendingOperations 清除其第一个元素和添加第二个元素之间存在竞争条件,但 load_contents_async 回调不会启动在主循环的下一次迭代之前被调用,所以你在那里应该是安全的。

关于javascript - 如何使用 GJS 安排一系列异步任务之后发生的事情?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32159589/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com